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,29 @@
|
||||
import { Q } from '../completion.mts';
|
||||
import type { ValueEvaluator } from '../evaluator.mts';
|
||||
import { OutOfRange } from '../helpers.mts';
|
||||
import type { ParseNode } from '../parser/ParseNode.mts';
|
||||
import { EvaluateStringOrNumericBinaryExpression } from './all.mts';
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-addition-operator-plus-runtime-semantics-evaluation */
|
||||
// AdditiveExpression : AdditiveExpression + MultiplicativeExpression
|
||||
function* Evaluate_AdditiveExpression_Plus({ AdditiveExpression, MultiplicativeExpression }: ParseNode.AdditiveExpression): ValueEvaluator {
|
||||
// 1. Return ? EvaluateStringOrNumericBinaryExpression(AdditiveExpression, +, MultiplicativeExpression).
|
||||
return Q(yield* EvaluateStringOrNumericBinaryExpression(AdditiveExpression, '+', MultiplicativeExpression));
|
||||
}
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-subtraction-operator-minus-runtime-semantics-evaluation */
|
||||
function* Evaluate_AdditiveExpression_Minus({ AdditiveExpression, MultiplicativeExpression }: ParseNode.AdditiveExpression): ValueEvaluator {
|
||||
// 1. Return ? EvaluateStringOrNumericBinaryExpression(AdditiveExpression, -, MultiplicativeExpression).
|
||||
return Q(yield* EvaluateStringOrNumericBinaryExpression(AdditiveExpression, '-', MultiplicativeExpression));
|
||||
}
|
||||
|
||||
export function* Evaluate_AdditiveExpression(AdditiveExpression: ParseNode.AdditiveExpression) {
|
||||
switch (AdditiveExpression.operator) {
|
||||
case '+':
|
||||
return yield* Evaluate_AdditiveExpression_Plus(AdditiveExpression);
|
||||
case '-':
|
||||
return yield* Evaluate_AdditiveExpression_Minus(AdditiveExpression);
|
||||
default:
|
||||
throw new OutOfRange('Evaluate_AdditiveExpression', AdditiveExpression);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
import {
|
||||
JSStringValue, Value,
|
||||
NumberValue,
|
||||
BigIntValue,
|
||||
SameType,
|
||||
} from '../value.mts';
|
||||
import { Q } from '../completion.mts';
|
||||
import {
|
||||
Assert, Throw, ToNumeric, ToPrimitive, ToString,
|
||||
} from '#self';
|
||||
|
||||
export type BinaryOperator = '+' | '-' | '*' | '/' | '%' | '**' | '<<' | '>>' | '>>>' | '&' | '^' | '|';
|
||||
/** https://tc39.es/ecma262/#sec-applystringornumericbinaryoperator */
|
||||
export function* ApplyStringOrNumericBinaryOperator(lval: Value, opText: BinaryOperator, rval: Value) {
|
||||
// 1. If opText is +, then
|
||||
if (opText === '+') {
|
||||
// a. Let lprim be ? ToPrimitive(lval).
|
||||
const lprim = Q(yield* ToPrimitive(lval));
|
||||
// b. Let rprim be ? ToPrimitive(rval).
|
||||
const rprim = Q(yield* ToPrimitive(rval));
|
||||
// c. If Type(lprim) is String or Type(rprim) is String, then
|
||||
if (lprim instanceof JSStringValue || rprim instanceof JSStringValue) {
|
||||
// i. Let lstr be ? ToString(lprim).
|
||||
const lstr = Q(yield* ToString(lprim));
|
||||
// ii. Let rstr be ? ToString(rprim).
|
||||
const rstr = Q(yield* ToString(rprim));
|
||||
// iii. Return the string-concatenation of lstr and rstr.
|
||||
return Value(lstr.stringValue() + rstr.stringValue());
|
||||
}
|
||||
// d. Set lval to lprim.
|
||||
lval = lprim;
|
||||
// e. Set rval to rprim.
|
||||
rval = rprim;
|
||||
}
|
||||
// 2. NOTE: At this point, it must be a numeric operation.
|
||||
// 3. Let lnum be ? ToNumeric(lval).
|
||||
const lnum = Q(yield* ToNumeric(lval));
|
||||
// 4. Let rnum be ? ToNumeric(rval).
|
||||
const rnum = Q(yield* ToNumeric(rval));
|
||||
// 5. If SameType(lNum, rNum) is false, throw a TypeError exception.
|
||||
if (!SameType(lnum, rnum)) {
|
||||
return Throw.TypeError('Cannot mix BigInt and other types in $1 operation', opText);
|
||||
}
|
||||
if (lnum instanceof BigIntValue) {
|
||||
const operations = {
|
||||
'**': BigIntValue.exponentiate,
|
||||
'*': BigIntValue.multiply,
|
||||
'/': BigIntValue.divide,
|
||||
'%': BigIntValue.remainder,
|
||||
'+': BigIntValue.add,
|
||||
'-': BigIntValue.subtract,
|
||||
'<<': BigIntValue.leftShift,
|
||||
'>>': BigIntValue.signedRightShift,
|
||||
'>>>': BigIntValue.unsignedRightShift,
|
||||
'&': BigIntValue.bitwiseAND,
|
||||
'^': BigIntValue.bitwiseXOR,
|
||||
'|': BigIntValue.bitwiseOR,
|
||||
};
|
||||
return Q(operations[opText](lnum, rnum as BigIntValue));
|
||||
} else {
|
||||
Assert(lnum instanceof NumberValue);
|
||||
const operations = {
|
||||
'**': NumberValue.exponentiate,
|
||||
'*': NumberValue.multiply,
|
||||
'/': NumberValue.divide,
|
||||
'%': NumberValue.remainder,
|
||||
'+': NumberValue.add,
|
||||
'-': NumberValue.subtract,
|
||||
'<<': NumberValue.leftShift,
|
||||
'>>': NumberValue.signedRightShift,
|
||||
'>>>': NumberValue.unsignedRightShift,
|
||||
'&': NumberValue.bitwiseAND,
|
||||
'^': NumberValue.bitwiseXOR,
|
||||
'|': NumberValue.bitwiseOR,
|
||||
};
|
||||
return Q(operations[opText](lnum, rnum as NumberValue));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,178 @@
|
||||
import { surroundingAgent } from '../host-defined/engine.mts';
|
||||
import {
|
||||
Value, Descriptor, type Arguments,
|
||||
} from '../value.mts';
|
||||
import { Evaluate, type PlainEvaluator } from '../evaluator.mts';
|
||||
import { Q, X } from '../completion.mts';
|
||||
import { OutOfRange, isArray } from '../helpers.mts';
|
||||
import { TemplateStrings } from '../static-semantics/all.mts';
|
||||
import type { ParseNode } from '../parser/ParseNode.mts';
|
||||
import {
|
||||
Assert,
|
||||
ArrayCreate,
|
||||
SetIntegrityLevel,
|
||||
ToString,
|
||||
GetIterator,
|
||||
GetValue,
|
||||
F,
|
||||
IteratorStepValue,
|
||||
} from '#self';
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-gettemplateobjec */
|
||||
function GetTemplateObject(templateLiteral: ParseNode.TemplateLiteral) {
|
||||
// 1. Let realm be the current Realm Record.
|
||||
const realm = surroundingAgent.currentRealmRecord;
|
||||
// 2. Let templateRegistry be realm.[[TemplateMap]].
|
||||
const templateRegistry = realm.TemplateMap;
|
||||
// 3. For each element e of templateRegistry, do
|
||||
for (const e of templateRegistry) {
|
||||
// a. If e.[[Site]] is the same Parse Node as templateLiteral, then
|
||||
if (e.Site === templateLiteral) {
|
||||
// b. Return e.[[Array]].
|
||||
return e.Array;
|
||||
}
|
||||
}
|
||||
// 4. Let rawStrings be TemplateStrings of templateLiteral with argument true.
|
||||
const rawStrings = TemplateStrings(templateLiteral, true);
|
||||
// 5. Let cookedStrings be TemplateStrings of templateLiteral with argument false.
|
||||
const cookedStrings = TemplateStrings(templateLiteral, false);
|
||||
// 6. Let count be the number of elements in the List cookedStrings.
|
||||
const count = cookedStrings.length;
|
||||
// 7. Assert: count ≤ 232 - 1.
|
||||
Assert(count < (2 ** 32) - 1);
|
||||
// 8. Let template be ! ArrayCreate(count).
|
||||
const template = X(ArrayCreate(count));
|
||||
// 9. Let template be ! ArrayCreate(count).
|
||||
const rawObj = X(ArrayCreate(count));
|
||||
// 10. Let index be 0.
|
||||
let index = 0;
|
||||
// 11. Repeat, while index < count
|
||||
while (index < count) {
|
||||
// a. Let prop be ! ToString(𝔽(index)).
|
||||
const prop = X(ToString(F(index)));
|
||||
// b. Let cookedValue be the String value cookedStrings[index].
|
||||
const cookedValue = cookedStrings[index];
|
||||
// c. Call template.[[DefineOwnProperty]](prop, PropertyDescriptor { [[Value]]: cookedValue, [[Writable]]: false, [[Enumerable]]: true, [[Configurable]]: false }).
|
||||
X(template.DefineOwnProperty(prop, Descriptor({
|
||||
Value: cookedValue,
|
||||
Writable: Value.false,
|
||||
Enumerable: Value.true,
|
||||
Configurable: Value.false,
|
||||
})));
|
||||
// d. Let rawValue be the String value rawStrings[index].
|
||||
const rawValue = rawStrings[index];
|
||||
// e. Call rawObj.[[DefineOwnProperty]](prop, PropertyDescriptor { [[Value]]: rawValue, [[Writable]]: false, [[Enumerable]]: true, [[Configurable]]: false }).
|
||||
X(rawObj.DefineOwnProperty(prop, Descriptor({
|
||||
Value: rawValue,
|
||||
Writable: Value.false,
|
||||
Enumerable: Value.true,
|
||||
Configurable: Value.false,
|
||||
})));
|
||||
// f. Call rawObj.[[DefineOwnProperty]](prop, PropertyDescriptor { [[Value]]: rawValue, [[Writable]]: false, [[Enumerable]]: true, [[Configurable]]: false }).
|
||||
index += 1;
|
||||
}
|
||||
// 12. Perform SetIntegrityLevel(rawObj, frozen).
|
||||
X(SetIntegrityLevel(rawObj, 'frozen'));
|
||||
// 13. Perform SetIntegrityLevel(rawObj, frozen).
|
||||
X(template.DefineOwnProperty(Value('raw'), Descriptor({
|
||||
Value: rawObj,
|
||||
Writable: Value.false,
|
||||
Enumerable: Value.false,
|
||||
Configurable: Value.false,
|
||||
})));
|
||||
// 14. Perform SetIntegrityLevel(template, frozen).
|
||||
X(SetIntegrityLevel(template, 'frozen'));
|
||||
// 15. Append the Record { [[Site]]: templateLiteral, [[Array]]: template } to templateRegistry.
|
||||
templateRegistry.push({ Site: templateLiteral, Array: template });
|
||||
// 16. Return template.
|
||||
return template;
|
||||
}
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-template-literals-runtime-semantics-argumentlistevaluation */
|
||||
// TemplateLiteral : NoSubstitutionTemplate
|
||||
//
|
||||
// https://github.com/tc39/ecma262/pull/1402
|
||||
// TemplateLiteral : SubstitutionTemplate
|
||||
function* ArgumentListEvaluation_TemplateLiteral(TemplateLiteral: ParseNode.TemplateLiteral): PlainEvaluator<Arguments> {
|
||||
switch (true) {
|
||||
case TemplateLiteral.TemplateSpanList.length === 1: {
|
||||
const templateLiteral = TemplateLiteral;
|
||||
const siteObj = GetTemplateObject(templateLiteral);
|
||||
return [siteObj] as Arguments;
|
||||
}
|
||||
|
||||
case TemplateLiteral.TemplateSpanList.length > 1: {
|
||||
const templateLiteral = TemplateLiteral;
|
||||
const siteObj = GetTemplateObject(templateLiteral);
|
||||
const restSub = [];
|
||||
for (const Expression of TemplateLiteral.ExpressionList) {
|
||||
const subRef = Q(yield* Evaluate(Expression));
|
||||
const subValue = Q(yield* GetValue(subRef));
|
||||
restSub.push(subValue);
|
||||
}
|
||||
return [siteObj, ...restSub] as Arguments;
|
||||
}
|
||||
|
||||
default:
|
||||
throw new OutOfRange('ArgumentListEvaluation_TemplateLiteral', TemplateLiteral);
|
||||
}
|
||||
}
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-argument-lists-runtime-semantics-argumentlistevaluation */
|
||||
// Arguments : `(` `)`
|
||||
// ArgumentList :
|
||||
// AssignmentExpression
|
||||
// `...` AssignmentExpression
|
||||
// ArgumentList `,` AssignmentExpression
|
||||
// ArgumentList `,` `...` AssignmentExpression
|
||||
//
|
||||
// (implicit)
|
||||
// Arguments :
|
||||
// `(` ArgumentList `)`
|
||||
// `(` ArgumentList `,` `)`
|
||||
function* ArgumentListEvaluation_Arguments(Arguments: ParseNode.Arguments): PlainEvaluator<Arguments> {
|
||||
const precedingArgs = [];
|
||||
for (const element of Arguments) {
|
||||
if (element.type === 'AssignmentRestElement') {
|
||||
const { AssignmentExpression } = element;
|
||||
// 2. Let spreadRef be the result of evaluating AssignmentExpression.
|
||||
const spreadRef = Q(yield* Evaluate(AssignmentExpression));
|
||||
// 3. Let spreadObj be ? GetValue(spreadRef).
|
||||
const spreadObj = Q(yield* GetValue(spreadRef));
|
||||
// 4. Let iteratorRecord be ? GetIterator(spreadObj).
|
||||
const iteratorRecord = Q(yield* GetIterator(spreadObj, 'sync'));
|
||||
// 5. Repeat,
|
||||
while (true) {
|
||||
// a. Let next be ? IteratorStepValue(iteratorRecord).
|
||||
const next = Q(yield* IteratorStepValue(iteratorRecord));
|
||||
// b. If next is false, return list.
|
||||
if (next === 'done') {
|
||||
break;
|
||||
}
|
||||
// d. Append next as the last element of list.
|
||||
precedingArgs.push(next);
|
||||
}
|
||||
} else {
|
||||
const AssignmentExpression = element;
|
||||
// 2. Let ref be the result of evaluating AssignmentExpression.
|
||||
const ref = Q(yield* Evaluate(AssignmentExpression));
|
||||
// 3. Let arg be ? GetValue(ref).
|
||||
const arg = Q(yield* GetValue(ref));
|
||||
// 4. Append arg to the end of precedingArgs.
|
||||
precedingArgs.push(arg);
|
||||
// 5. Return precedingArgs.
|
||||
}
|
||||
}
|
||||
return precedingArgs as Arguments;
|
||||
}
|
||||
|
||||
export function ArgumentListEvaluation(ArgumentsOrTemplateLiteral: ParseNode | ParseNode.Arguments) {
|
||||
switch (true) {
|
||||
case isArray(ArgumentsOrTemplateLiteral):
|
||||
return ArgumentListEvaluation_Arguments(ArgumentsOrTemplateLiteral);
|
||||
case ('type' in ArgumentsOrTemplateLiteral && ArgumentsOrTemplateLiteral.type === 'TemplateLiteral'):
|
||||
return ArgumentListEvaluation_TemplateLiteral(ArgumentsOrTemplateLiteral);
|
||||
default:
|
||||
throw new OutOfRange('ArgumentListEvaluation', ArgumentsOrTemplateLiteral);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
import { ObjectValue, Value } from '../value.mts';
|
||||
import {
|
||||
Evaluate, type PlainEvaluator,
|
||||
type ValueEvaluator,
|
||||
} from '../evaluator.mts';
|
||||
import {
|
||||
Q, X,
|
||||
} from '../completion.mts';
|
||||
import type { ParseNode } from '../parser/ParseNode.mts';
|
||||
import {
|
||||
Set,
|
||||
ArrayCreate,
|
||||
GetValue,
|
||||
GetIterator,
|
||||
ToString,
|
||||
CreateDataPropertyOrThrow,
|
||||
F,
|
||||
IteratorStepValue,
|
||||
} from '#self';
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-runtime-semantics-arrayaccumulation */
|
||||
// Elision :
|
||||
// `,`
|
||||
// Elision `,`
|
||||
// ElementList :
|
||||
// Elision? AssignmentExpression
|
||||
// Elision? SpreadElement
|
||||
// ElementList `,` Elision? AssignmentExpression
|
||||
// ElementList : ElementList `,` Elision SpreadElement
|
||||
// SpreadElement :
|
||||
// `...` AssignmentExpression
|
||||
function* ArrayAccumulation(ElementList: ParseNode.ElementList, array: ObjectValue, nextIndex: number): PlainEvaluator<number> {
|
||||
let postIndex = nextIndex;
|
||||
for (const element of ElementList) {
|
||||
switch (element.type) {
|
||||
case 'Elision':
|
||||
postIndex += 1;
|
||||
Q(yield* Set(array, Value('length'), F(postIndex), Value.true));
|
||||
break;
|
||||
case 'SpreadElement':
|
||||
postIndex = Q(yield* ArrayAccumulation_SpreadElement(element, array, postIndex));
|
||||
break;
|
||||
default:
|
||||
postIndex = Q(yield* ArrayAccumulation_AssignmentExpression(element, array, postIndex));
|
||||
break;
|
||||
}
|
||||
}
|
||||
return postIndex;
|
||||
}
|
||||
|
||||
// SpreadElement : `...` AssignmentExpression
|
||||
function* ArrayAccumulation_SpreadElement({ AssignmentExpression }: ParseNode.SpreadElement, array: ObjectValue, nextIndex: number): PlainEvaluator<number> {
|
||||
// 1. Let spreadRef be the result of evaluating AssignmentExpression.
|
||||
const spreadRef = Q(yield* Evaluate(AssignmentExpression));
|
||||
// 2. Let spreadObj be ? GetValue(spreadRef).
|
||||
const spreadObj = Q(yield* GetValue(spreadRef));
|
||||
// 3. Let iteratorRecord be ? GetIterator(spreadObj).
|
||||
const iteratorRecord = Q(yield* GetIterator(spreadObj, 'sync'));
|
||||
// 4. Repeat,
|
||||
while (true) {
|
||||
// a. Let next be ? IteratorStep(iteratorRecord).
|
||||
const next = Q(yield* IteratorStepValue(iteratorRecord));
|
||||
// b. If next is done, return nextIndex.
|
||||
if (next === 'done') {
|
||||
return nextIndex;
|
||||
}
|
||||
// d. Perform ! CreateDataPropertyOrThrow(array, ! ToString(𝔽(nextIndex)), next).
|
||||
X(CreateDataPropertyOrThrow(array, X(ToString(F(nextIndex))), next));
|
||||
// e. Set nextIndex to nextIndex + 1.
|
||||
nextIndex += 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function* ArrayAccumulation_AssignmentExpression(AssignmentExpression: ParseNode.AssignmentExpressionOrHigher, array: ObjectValue, nextIndex: number): PlainEvaluator<number> {
|
||||
// 2. Let initResult be the result of evaluating AssignmentExpression.
|
||||
const initResult = Q(yield* Evaluate(AssignmentExpression));
|
||||
// 3. Let initValue be ? GetValue(initResult).
|
||||
const initValue = Q(yield* GetValue(initResult));
|
||||
// 4. Let created be ! CreateDataPropertyOrThrow(array, ! ToString(𝔽(nextIndex)), initValue).
|
||||
X(CreateDataPropertyOrThrow(array, X(ToString(F(nextIndex))), initValue));
|
||||
// 5. Return nextIndex + 1.
|
||||
return nextIndex + 1;
|
||||
}
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-array-initializer-runtime-semantics-evaluation */
|
||||
// ArrayLiteral :
|
||||
// `[` Elision `]`
|
||||
// `[` ElementList `]`
|
||||
// `[` ElementList `,` Elision `]`
|
||||
export function* Evaluate_ArrayLiteral({ ElementList }: ParseNode.ArrayLiteral): ValueEvaluator {
|
||||
// 1. Let array be ! ArrayCreate(0).
|
||||
const array = X(ArrayCreate(0));
|
||||
// 2. Let len be the result of performing ArrayAccumulation for ElementList with arguments array and 0.
|
||||
const len = yield* ArrayAccumulation(ElementList, array, 0);
|
||||
Q(len);
|
||||
// 4. Return array.
|
||||
return array;
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
import type { ParseNode } from '../parser/ParseNode.mts';
|
||||
import { InstantiateArrowFunctionExpression } from './all.mts';
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-arrow-function-definitions-runtime-semantics-evaluation */
|
||||
export function Evaluate_ArrowFunction(ArrowFunction: ParseNode.ArrowFunction) {
|
||||
// 1. Return InstantiateArrowFunctionExpression of ArrowFunction.
|
||||
return InstantiateArrowFunctionExpression(ArrowFunction);
|
||||
}
|
||||
@@ -0,0 +1,281 @@
|
||||
import { JSStringValue, ReferenceRecord, Value } from '../value.mts';
|
||||
import { Q, X } from '../completion.mts';
|
||||
import {
|
||||
IsAnonymousFunctionDefinition,
|
||||
IsIdentifierRef,
|
||||
type DestructuringParseNode,
|
||||
type FunctionDeclaration,
|
||||
} from '../static-semantics/all.mts';
|
||||
import { Evaluate, type ValueEvaluator } from '../evaluator.mts';
|
||||
import { OutOfRange } from '../helpers.mts';
|
||||
import type { ParseNode } from '../parser/ParseNode.mts';
|
||||
import {
|
||||
NamedEvaluation,
|
||||
ApplyStringOrNumericBinaryOperator,
|
||||
DestructuringAssignmentEvaluation,
|
||||
} from './all.mts';
|
||||
import {
|
||||
GetValue,
|
||||
PutValue,
|
||||
ToBoolean,
|
||||
} from '#self';
|
||||
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-destructuring-assignment */
|
||||
export function refineLeftHandSideExpression(node: ParseNode.ArrayLiteral | ParseNode.ObjectLiteral | ParseNode.PropertyDefinition | ParseNode.MemberExpression | ParseNode.CoverInitializedName | ParseNode.AssignmentExpression | ParseNode.Elision | ParseNode.IdentifierReference | ParseNode.ElementListElement | DestructuringParseNode, type?: 'array' | 'object'): ParseNode.AssignmentPattern {
|
||||
switch (node.type) {
|
||||
case 'ArrayLiteral': {
|
||||
const refinement: ParseNode.ArrayAssignmentPattern = {
|
||||
type: 'ArrayAssignmentPattern',
|
||||
AssignmentElementList: [],
|
||||
AssignmentRestElement: undefined,
|
||||
};
|
||||
node.ElementList.forEach((n) => {
|
||||
switch (n.type) {
|
||||
case 'SpreadElement':
|
||||
refinement.AssignmentRestElement = {
|
||||
...n,
|
||||
type: 'AssignmentRestElement',
|
||||
AssignmentExpression: n.AssignmentExpression,
|
||||
};
|
||||
break;
|
||||
case 'ArrayLiteral':
|
||||
case 'ObjectLiteral':
|
||||
refinement.AssignmentElementList.push({
|
||||
type: 'AssignmentElement',
|
||||
DestructuringAssignmentTarget: n,
|
||||
Initializer: null,
|
||||
});
|
||||
break;
|
||||
default:
|
||||
refinement.AssignmentElementList.push(refineLeftHandSideExpression(n, 'array'));
|
||||
break;
|
||||
}
|
||||
});
|
||||
return refinement;
|
||||
}
|
||||
case 'ObjectLiteral': {
|
||||
const refined: ParseNode.ObjectAssignmentPattern = {
|
||||
type: 'ObjectAssignmentPattern',
|
||||
AssignmentPropertyList: [],
|
||||
AssignmentRestProperty: undefined,
|
||||
};
|
||||
node.PropertyDefinitionList.forEach((p) => {
|
||||
if ((p as ParseNode.PropertyDefinition).PropertyName === null && (p as ParseNode.PropertyDefinition).AssignmentExpression) {
|
||||
refined.AssignmentRestProperty = {
|
||||
type: 'AssignmentRestProperty',
|
||||
DestructuringAssignmentTarget: (p as ParseNode.PropertyDefinition).AssignmentExpression,
|
||||
};
|
||||
} else {
|
||||
refined.AssignmentPropertyList.push(refineLeftHandSideExpression(p as ParseNode.PropertyDefinition, 'object'));
|
||||
}
|
||||
});
|
||||
return refined;
|
||||
}
|
||||
case 'PropertyDefinition':
|
||||
return {
|
||||
type: 'AssignmentProperty',
|
||||
PropertyName: node.PropertyName,
|
||||
AssignmentElement: node.AssignmentExpression.type === 'AssignmentExpression'
|
||||
? {
|
||||
type: 'AssignmentElement',
|
||||
DestructuringAssignmentTarget: node.AssignmentExpression.LeftHandSideExpression,
|
||||
Initializer: node.AssignmentExpression.AssignmentExpression,
|
||||
}
|
||||
: {
|
||||
type: 'AssignmentElement',
|
||||
DestructuringAssignmentTarget: node.AssignmentExpression,
|
||||
Initializer: undefined,
|
||||
},
|
||||
};
|
||||
case 'IdentifierReference':
|
||||
if (type === 'array') {
|
||||
return {
|
||||
type: 'AssignmentElement',
|
||||
DestructuringAssignmentTarget: node,
|
||||
Initializer: undefined,
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
type: 'AssignmentProperty',
|
||||
IdentifierReference: node,
|
||||
Initializer: undefined,
|
||||
};
|
||||
}
|
||||
case 'MemberExpression':
|
||||
return {
|
||||
type: 'AssignmentElement',
|
||||
DestructuringAssignmentTarget: node,
|
||||
Initializer: undefined,
|
||||
};
|
||||
case 'CoverInitializedName':
|
||||
return {
|
||||
type: 'AssignmentProperty',
|
||||
IdentifierReference: node.IdentifierReference,
|
||||
Initializer: node.Initializer,
|
||||
};
|
||||
case 'AssignmentExpression':
|
||||
return {
|
||||
type: 'AssignmentElement',
|
||||
DestructuringAssignmentTarget: node.LeftHandSideExpression,
|
||||
Initializer: node.AssignmentExpression,
|
||||
};
|
||||
case 'Elision':
|
||||
return node;
|
||||
default:
|
||||
throw new OutOfRange('refineLeftHandSideExpression', node.type);
|
||||
}
|
||||
}
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-assignment-operators-runtime-semantics-evaluation */
|
||||
// AssignmentExpression :
|
||||
// LeftHandSideExpression `=` AssignmentExpression
|
||||
// LeftHandSideExpression AssignmentOperator AssignmentExpression
|
||||
// LeftHandSideExpression `&&=` AssignmentExpression
|
||||
// LeftHandSideExpression `||=` AssignmentExpression
|
||||
// LeftHandSideExpression `??=` AssignmentExpression
|
||||
export function* Evaluate_AssignmentExpression({
|
||||
LeftHandSideExpression, AssignmentOperator, AssignmentExpression,
|
||||
}: ParseNode.AssignmentExpression): ValueEvaluator {
|
||||
if (AssignmentOperator === '=') {
|
||||
// 1. If LeftHandSideExpression is neither an ObjectLiteral nor an ArrayLiteral, then
|
||||
if (LeftHandSideExpression.type !== 'ObjectLiteral' && LeftHandSideExpression.type !== 'ArrayLiteral') {
|
||||
// a. Let lref be the result of evaluating LeftHandSideExpression.
|
||||
const lref = Q(yield* Evaluate(LeftHandSideExpression));
|
||||
Q(lref);
|
||||
// c. If IsAnonymousFunctionDefinition(AssignmentExpression) and IsIdentifierRef of LeftHandSideExpression are both true, then
|
||||
let rval;
|
||||
if (IsAnonymousFunctionDefinition(AssignmentExpression) && IsIdentifierRef(LeftHandSideExpression)) {
|
||||
// i. Let rval be NamedEvaluation of AssignmentExpression with argument GetReferencedName(lref).
|
||||
rval = Q(yield* NamedEvaluation(AssignmentExpression as FunctionDeclaration, (lref as ReferenceRecord).ReferencedName as JSStringValue));
|
||||
} else { // d. Else,
|
||||
// i. Let rref be the result of evaluating AssignmentExpression.
|
||||
const rref = Q(yield* Evaluate(AssignmentExpression));
|
||||
// ii. Let rval be ? GetValue(rref).
|
||||
rval = Q(yield* GetValue(rref));
|
||||
}
|
||||
// e. Perform ? PutValue(lref, rval).
|
||||
Q(yield* PutValue(lref, rval));
|
||||
// f. Return rval.
|
||||
return rval;
|
||||
}
|
||||
// 2. Let assignmentPattern be the AssignmentPattern that is covered by LeftHandSideExpression.
|
||||
const assignmentPattern = refineLeftHandSideExpression(LeftHandSideExpression);
|
||||
// 3. Let rref be the result of evaluating AssignmentExpression.
|
||||
const rref = Q(yield* Evaluate(AssignmentExpression));
|
||||
// 3. Let rval be ? GetValue(rref).
|
||||
const rval = Q(yield* GetValue(rref));
|
||||
// 4. Perform ? DestructuringAssignmentEvaluation of assignmentPattern using rval as the argument.
|
||||
Q(yield* DestructuringAssignmentEvaluation(assignmentPattern as ParseNode.ObjectAssignmentPattern | ParseNode.ArrayAssignmentPattern, rval));
|
||||
// 5. Return rval.
|
||||
return rval;
|
||||
} else if (AssignmentOperator === '&&=') {
|
||||
// 1. Let lref be the result of evaluating LeftHandSideExpression.
|
||||
const lref = Q(yield* Evaluate(LeftHandSideExpression));
|
||||
// 2. Let lval be ? GetValue(lref).
|
||||
const lval = Q(yield* GetValue(lref));
|
||||
// 3. Let lbool be ! ToBoolean(lval).
|
||||
const lbool = X(ToBoolean(lval));
|
||||
// 4. If lbool is false, return lval.
|
||||
if (lbool === Value.false) {
|
||||
return lval;
|
||||
}
|
||||
let rval;
|
||||
// 5. If IsAnonymousFunctionDefinition(AssignmentExpression) is true and IsIdentifierRef of LeftHandSideExpression is true, then
|
||||
if (IsAnonymousFunctionDefinition(AssignmentExpression) && IsIdentifierRef(LeftHandSideExpression)) {
|
||||
// a. Let rval be NamedEvaluation of AssignmentExpression with argument GetReferencedName(lref).
|
||||
rval = Q(yield* NamedEvaluation(AssignmentExpression as FunctionDeclaration, (lref as ReferenceRecord).ReferencedName as JSStringValue));
|
||||
} else { // 6. Else,
|
||||
// a. Let rref be the result of evaluating AssignmentExpression.
|
||||
const rref = Q(yield* Evaluate(AssignmentExpression));
|
||||
// b. Let rval be ? GetValue(rref).
|
||||
rval = Q(yield* GetValue(rref));
|
||||
}
|
||||
// 7. Perform ? PutValue(lref, rval).
|
||||
Q(yield* PutValue(lref, rval));
|
||||
// 8. Return rval.
|
||||
return rval;
|
||||
} else if (AssignmentOperator === '||=') {
|
||||
// 1. Let lref be the result of evaluating LeftHandSideExpression.
|
||||
const lref = Q(yield* Evaluate(LeftHandSideExpression));
|
||||
// 2. Let lval be ? GetValue(lref).
|
||||
const lval = Q(yield* GetValue(lref));
|
||||
// 3. Let lbool be ! ToBoolean(lval).
|
||||
const lbool = X(ToBoolean(lval));
|
||||
// 4. If lbool is true, return lval.
|
||||
if (lbool === Value.true) {
|
||||
return lval;
|
||||
}
|
||||
let rval;
|
||||
// 5. If IsAnonymousFunctionDefinition(AssignmentExpression) is true and IsIdentifierRef of LeftHandSideExpression is true, then
|
||||
if (IsAnonymousFunctionDefinition(AssignmentExpression) && IsIdentifierRef(LeftHandSideExpression)) {
|
||||
// a. Let rval be NamedEvaluation of AssignmentExpression with argument GetReferencedName(lref).
|
||||
rval = Q(yield* NamedEvaluation(AssignmentExpression as FunctionDeclaration, (lref as ReferenceRecord).ReferencedName as JSStringValue));
|
||||
} else { // 6. Else,
|
||||
// a. Let rref be the result of evaluating AssignmentExpression.
|
||||
const rref = Q(yield* Evaluate(AssignmentExpression));
|
||||
// b. Let rval be ? GetValue(rref).
|
||||
rval = Q(yield* GetValue(rref));
|
||||
}
|
||||
// 7. Perform ? PutValue(lref, rval).
|
||||
Q(yield* PutValue(lref, rval));
|
||||
// 8. Return rval.
|
||||
return rval;
|
||||
} else if (AssignmentOperator === '??=') {
|
||||
// 1.Let lref be the result of evaluating LeftHandSideExpression.
|
||||
const lref = Q(yield* Evaluate(LeftHandSideExpression));
|
||||
// 2. Let lval be ? GetValue(lref).
|
||||
const lval = Q(yield* GetValue(lref));
|
||||
// 3. If lval is not undefined nor null, return lval.
|
||||
if (lval !== Value.undefined && lval !== Value.null) {
|
||||
return lval;
|
||||
}
|
||||
let rval;
|
||||
// 4. If IsAnonymousFunctionDefinition(AssignmentExpression) is true and IsIdentifierRef of LeftHandSideExpression is true, then
|
||||
if (IsAnonymousFunctionDefinition(AssignmentExpression) && IsIdentifierRef(LeftHandSideExpression)) {
|
||||
// a. Let rval be NamedEvaluation of AssignmentExpression with argument GetReferencedName(lref).
|
||||
rval = Q(yield* NamedEvaluation(AssignmentExpression as FunctionDeclaration, (lref as ReferenceRecord).ReferencedName as JSStringValue));
|
||||
} else { // 5. Else,
|
||||
// a. Let rref be the result of evaluating AssignmentExpression.
|
||||
const rref = Q(yield* Evaluate(AssignmentExpression));
|
||||
// b. Let rval be ? GetValue(rref).
|
||||
rval = Q(yield* GetValue(rref));
|
||||
}
|
||||
// 6. Perform ? PutValue(lref, rval).
|
||||
Q(yield* PutValue(lref, rval));
|
||||
// 7. Return rval.
|
||||
return rval;
|
||||
} else {
|
||||
// 1. Let lref be the result of evaluating LeftHandSideExpression.
|
||||
const lref = Q(yield* Evaluate(LeftHandSideExpression));
|
||||
// 2. Let lval be ? GetValue(lref).
|
||||
const lval = Q(yield* GetValue(lref));
|
||||
// 3. Let rref be the result of evaluating AssignmentExpression.
|
||||
const rref = Q(yield* Evaluate(AssignmentExpression));
|
||||
// 4. Let rval be ? GetValue(rref).
|
||||
const rval = Q(yield* GetValue(rref));
|
||||
// 5. Let assignmentOpText be the source text matched by AssignmentOperator.
|
||||
const assignmentOpText = AssignmentOperator;
|
||||
// 6. Let opText be the sequence of Unicode code points associated with assignmentOpText in the following table:
|
||||
const opText = ({
|
||||
'**=': '**',
|
||||
'*=': '*',
|
||||
'/=': '/',
|
||||
'%=': '%',
|
||||
'+=': '+',
|
||||
'-=': '-',
|
||||
'<<=': '<<',
|
||||
'>>=': '>>',
|
||||
'>>>=': '>>>',
|
||||
'&=': '&',
|
||||
'^=': '^',
|
||||
'|=': '|',
|
||||
} as const)[assignmentOpText];
|
||||
// 7. Let r be ApplyStringOrNumericBinaryOperator(lval, opText, rval).
|
||||
const r = Q(yield* ApplyStringOrNumericBinaryOperator(lval, opText, rval));
|
||||
// 8. Perform ? PutValue(lref, r).
|
||||
Q(yield* PutValue(lref, r));
|
||||
// 9. Return r.
|
||||
return r;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
import type { ParseNode } from '../parser/ParseNode.mts';
|
||||
import { InstantiateAsyncArrowFunctionExpression } from './all.mts';
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-async-arrow-function-definitions-runtime-semantics-evaluation */
|
||||
export function Evaluate_AsyncArrowFunction(AsyncArrowFunction: ParseNode.AsyncArrowFunction) {
|
||||
// 1. Return InstantiateAsyncArrowFunctionExpression of AsyncArrowFunction.
|
||||
return InstantiateAsyncArrowFunctionExpression(AsyncArrowFunction);
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
import type { ParseNode } from '../parser/ParseNode.mts';
|
||||
import { InstantiateAsyncFunctionExpression } from './all.mts';
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-async-function-definitions-runtime-semantics-evaluation */
|
||||
// AsyncFunctionExpression :
|
||||
// `async` `function` `(` FormalParameters `)` `{` AsyncBody `}`
|
||||
// `async` `function` BindingIdentifier `(` FormalParameters `)` `{` AsyncBody `}`
|
||||
export function Evaluate_AsyncFunctionExpression(AsyncFunctionExpression: ParseNode.AsyncFunctionExpression) {
|
||||
// 1. Return InstantiateAsyncFunctionExpression of AsyncFunctionExpression.
|
||||
return InstantiateAsyncFunctionExpression(AsyncFunctionExpression);
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
import type { ParseNode } from '../parser/ParseNode.mts';
|
||||
import { InstantiateAsyncGeneratorFunctionExpression } from './all.mts';
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-asyncgenerator-definitions-evaluation */
|
||||
// AsyncGeneratorExpression :
|
||||
// `async` `function` `*` `(` FormalParameters `)` `{` AsyncGeneratorBody `}`
|
||||
// `async` `function` `*` BindingIdentifier `(` FormalParameters `)` `{` AsyncGeneratorBody `}`
|
||||
export function Evaluate_AsyncGeneratorExpression(AsyncGeneratorExpression: ParseNode.AsyncGeneratorExpression) {
|
||||
// 1. Return InstantiateAsyncGeneratorFunctionExpression of AsyncGeneratorExpression.
|
||||
return InstantiateAsyncGeneratorFunctionExpression(AsyncGeneratorExpression);
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
import { Evaluate, type ValueEvaluator } from '../evaluator.mts';
|
||||
import { Await, Q } from '../completion.mts';
|
||||
import type { ParseNode } from '../parser/ParseNode.mts';
|
||||
import { GetValue, surroundingAgent } from '#self';
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-async-function-definitions-runtime-semantics-evaluation */
|
||||
// AwaitExpression : `await` UnaryExpression
|
||||
export function* Evaluate_AwaitExpression({ UnaryExpression }: ParseNode.AwaitExpression): ValueEvaluator {
|
||||
Q(surroundingAgent.debugger_cannotPreview);
|
||||
// 1. Let exprRef be the result of evaluating UnaryExpression.
|
||||
const exprRef = Q(yield* Evaluate(UnaryExpression));
|
||||
// 2. Let value be ? GetValue(exprRef).
|
||||
const value = Q(yield* GetValue(exprRef));
|
||||
// 3. Return ? Await(value).
|
||||
return Q(yield* Await(value));
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
import { JSStringValue, Value } from '../value.mts';
|
||||
import {
|
||||
EnsureCompletion,
|
||||
EnvironmentRecord, StringValue, UndefinedValue,
|
||||
} from '../index.mts';
|
||||
import { NormalCompletion, Q } from '../completion.mts';
|
||||
import { OutOfRange } from '../helpers.mts';
|
||||
import type { ParseNode } from '../parser/ParseNode.mts';
|
||||
import type { PlainEvaluator } from '../evaluator.mts';
|
||||
import {
|
||||
IteratorBindingInitialization_ArrayBindingPattern,
|
||||
PropertyBindingInitialization,
|
||||
RestBindingInitialization,
|
||||
} from './all.mts';
|
||||
import {
|
||||
Assert,
|
||||
PutValue,
|
||||
ResolveBinding,
|
||||
RequireObjectCoercible,
|
||||
GetIterator,
|
||||
IteratorClose,
|
||||
} from '#self';
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-initializeboundname */
|
||||
export function* InitializeBoundName(name: JSStringValue, value: Value, environment: EnvironmentRecord | UndefinedValue): PlainEvaluator {
|
||||
// 1. Assert: Type(name) is String.
|
||||
Assert(name instanceof JSStringValue);
|
||||
// 2. If environment is not undefined, then
|
||||
if (!(environment instanceof UndefinedValue)) {
|
||||
// a. Perform environment.InitializeBinding(name, value).
|
||||
yield* environment.InitializeBinding(name, value);
|
||||
// b. Return NormalCompletion(undefined).
|
||||
return NormalCompletion(undefined);
|
||||
} else {
|
||||
// a. Let lhs be ResolveBinding(name).
|
||||
const lhs = Q(yield* ResolveBinding(name, undefined, false));
|
||||
// b. Return ? PutValue(lhs, value).
|
||||
return Q(yield* PutValue(lhs, value));
|
||||
}
|
||||
}
|
||||
|
||||
// ObjectBindingPattern :
|
||||
// `{` `}`
|
||||
// `{` BindingPropertyList `}`
|
||||
// `{` BindingRestProperty `}`
|
||||
// `{` BindingPropertyList `,` BindingRestProperty `}`
|
||||
function* BindingInitialization_ObjectBindingPattern({ BindingPropertyList, BindingRestProperty }: ParseNode.ObjectBindingPattern, value: Value, environment: EnvironmentRecord | UndefinedValue): PlainEvaluator {
|
||||
// 1. Perform ? PropertyBindingInitialization for BindingPropertyList using value and environment as the arguments.
|
||||
const excludedNames = Q(yield* PropertyBindingInitialization(BindingPropertyList, value, environment));
|
||||
if (BindingRestProperty) {
|
||||
Q(yield* RestBindingInitialization(BindingRestProperty, value, environment, excludedNames));
|
||||
}
|
||||
// 2. Return NormalCompletion(empty).
|
||||
return NormalCompletion(undefined);
|
||||
}
|
||||
|
||||
export function* BindingInitialization(node: ParseNode.ForBinding | ParseNode.ForDeclaration | ParseNode.BindingIdentifier | ParseNode.ObjectBindingPattern | ParseNode.ArrayBindingPattern | ParseNode.BindingPattern, value: Value, environment: EnvironmentRecord | UndefinedValue): PlainEvaluator {
|
||||
switch (node.type) {
|
||||
case 'ForBinding':
|
||||
if (node.BindingIdentifier) {
|
||||
return yield* BindingInitialization(node.BindingIdentifier, value, environment);
|
||||
}
|
||||
return yield* BindingInitialization(node.BindingPattern!, value, environment);
|
||||
case 'ForDeclaration':
|
||||
return yield* BindingInitialization(node.ForBinding, value, environment);
|
||||
case 'BindingIdentifier': {
|
||||
// 1. Let name be StringValue of Identifier.
|
||||
const name = StringValue(node);
|
||||
// 2. Return ? InitializeBoundName(name, value, environment).
|
||||
return Q(yield* InitializeBoundName(name, value, environment));
|
||||
}
|
||||
case 'ObjectBindingPattern': {
|
||||
// 1. Perform ? RequireObjectCoercible(value).
|
||||
Q(RequireObjectCoercible(value));
|
||||
// 2. Return the result of performing BindingInitialization for ObjectBindingPattern using value and environment as arguments.
|
||||
return yield* BindingInitialization_ObjectBindingPattern(node, value, environment);
|
||||
}
|
||||
case 'ArrayBindingPattern': {
|
||||
// 1. Let iteratorRecord be ? GetIterator(value).
|
||||
const iteratorRecord = Q(yield* GetIterator(value, 'sync'));
|
||||
// 2. Let result be IteratorBindingInitialization of ArrayBindingPattern with arguments iteratorRecord and environment.
|
||||
const result = EnsureCompletion(yield* IteratorBindingInitialization_ArrayBindingPattern(node, iteratorRecord, environment));
|
||||
// 3. If iteratorRecord.[[Done]] is false, return ? IteratorClose(iteratorRecord, result).
|
||||
if (iteratorRecord.Done === Value.false) {
|
||||
return Q(yield* IteratorClose(iteratorRecord, result));
|
||||
}
|
||||
// 4. Return ? result.
|
||||
return result;
|
||||
}
|
||||
default:
|
||||
throw new OutOfRange('BindingInitialization', node);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
import { Q } from '../completion.mts';
|
||||
import type { ValueEvaluator } from '../evaluator.mts';
|
||||
import type { ParseNode } from '../parser/ParseNode.mts';
|
||||
import { EvaluateStringOrNumericBinaryExpression } from './all.mts';
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-binary-bitwise-operators-runtime-semantics-evaluation */
|
||||
// BitwiseANDExpression : BitwiseANDExpression `&` EqualityExpression
|
||||
// BitwiseXORExpression : BitwiseXORExpression `^` BitwiseANDExpression
|
||||
// BitwiseORExpression : BitwiseORExpression `|` BitwiseXORExpression
|
||||
// The production A : A @ B, where @ is one of the bitwise operators in the
|
||||
// productions above, is evaluated as follows:
|
||||
export function* Evaluate_BinaryBitwiseExpression({ A, operator, B }: ParseNode.BitwiseANDExpression | ParseNode.BitwiseXORExpression | ParseNode.BitwiseORExpression): ValueEvaluator {
|
||||
return Q(yield* EvaluateStringOrNumericBinaryExpression(A, operator, B));
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
import { surroundingAgent } from '../host-defined/engine.mts';
|
||||
import { Value } from '../value.mts';
|
||||
import {
|
||||
LexicallyScopedDeclarations,
|
||||
IsConstantDeclaration,
|
||||
BoundNames,
|
||||
} from '../static-semantics/all.mts';
|
||||
import { X, NormalCompletion } from '../completion.mts';
|
||||
import type { ParseNode } from '../parser/ParseNode.mts';
|
||||
import { Evaluate_StatementList, InstantiateFunctionObject } from './all.mts';
|
||||
import { Assert, DeclarativeEnvironmentRecord } from '#self';
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-blockdeclarationinstantiation */
|
||||
export function* BlockDeclarationInstantiation(code: ParseNode.StatementList | ParseNode.CaseBlock, env: DeclarativeEnvironmentRecord) {
|
||||
// 1. Assert: env is a declarative Environment Record.
|
||||
Assert(env instanceof DeclarativeEnvironmentRecord);
|
||||
// 2. Let declarations be the LexicallyScopedDeclarations of code.
|
||||
const declarations = LexicallyScopedDeclarations(code);
|
||||
// 3. Let privateEnv be the running execution context's PrivateEnvironment.
|
||||
const privateEnv = surroundingAgent.runningExecutionContext.PrivateEnvironment;
|
||||
// 4. For each element d in declarations, do
|
||||
for (const d of declarations) {
|
||||
// a. For each element dn of the BoundNames of d, do
|
||||
for (const dn of BoundNames(d)) {
|
||||
// i. If IsConstantDeclaration of d is true, then
|
||||
if (IsConstantDeclaration(d)) {
|
||||
// 1. Perform ! env.CreateImmutableBinding(dn, true).
|
||||
X(env.CreateImmutableBinding(dn, Value.true));
|
||||
} else { // ii. Else,
|
||||
// 1. Perform ! env.CreateMutableBinding(dn, false).
|
||||
X(env.CreateMutableBinding(dn, Value.false));
|
||||
}
|
||||
// b. If d is a FunctionDeclaration, a GeneratorDeclaration, an AsyncFunctionDeclaration, or an AsyncGeneratorDeclaration, then
|
||||
if (d.type === 'FunctionDeclaration'
|
||||
|| d.type === 'GeneratorDeclaration'
|
||||
|| d.type === 'AsyncFunctionDeclaration'
|
||||
|| d.type === 'AsyncGeneratorDeclaration') {
|
||||
// i. Let fn be the sole element of the BoundNames of d.
|
||||
const fn = BoundNames(d)[0];
|
||||
// ii. Let fo be InstantiateFunctionObject of d with argument env.
|
||||
const fo = InstantiateFunctionObject(d, env, privateEnv);
|
||||
// iii. Perform env.InitializeBinding(fn, fo).
|
||||
yield* env.InitializeBinding(fn, fo);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-block-runtime-semantics-evaluation */
|
||||
// Block :
|
||||
// `{` `}`
|
||||
// `{` StatementList `}`
|
||||
export function* Evaluate_Block({ StatementList }: ParseNode.Block) {
|
||||
if (StatementList.length === 0) {
|
||||
// 1. Return NormalCompletion(empty).
|
||||
return NormalCompletion(undefined);
|
||||
}
|
||||
// 1. Let oldEnv be the running execution context's LexicalEnvironment.
|
||||
const oldEnv = surroundingAgent.runningExecutionContext.LexicalEnvironment;
|
||||
// 2. Let blockEnv be NewDeclarativeEnvironment(oldEnv).
|
||||
const blockEnv = new DeclarativeEnvironmentRecord(oldEnv);
|
||||
// 3. Perform BlockDeclarationInstantiation(StatementList, blockEnv).
|
||||
yield* BlockDeclarationInstantiation(StatementList, blockEnv);
|
||||
// 4. Set the running execution context's LexicalEnvironment to blockEnv.
|
||||
surroundingAgent.runningExecutionContext.LexicalEnvironment = blockEnv;
|
||||
// 5. Let blockValue be the result of evaluating StatementList.
|
||||
const blockValue = yield* Evaluate_StatementList(StatementList);
|
||||
// 6. Set the running execution context's LexicalEnvironment to oldEnv.
|
||||
surroundingAgent.runningExecutionContext.LexicalEnvironment = oldEnv;
|
||||
// 7. Return blockValue.
|
||||
return blockValue;
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
import { Completion } from '../completion.mts';
|
||||
import type { ParseNode } from '../parser/ParseNode.mts';
|
||||
import { StringValue } from '../static-semantics/all.mts';
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-break-statement-runtime-semantics-evaluation */
|
||||
// BreakStatement :
|
||||
// `break` `;`
|
||||
// `break` LabelIdentifier `;`
|
||||
export function Evaluate_BreakStatement({ LabelIdentifier }: ParseNode.BreakStatement) {
|
||||
if (!LabelIdentifier) {
|
||||
// 1. Return Completion { [[Type]]: break, [[Value]]: empty, [[Target]]: empty }.
|
||||
return new Completion({ Type: 'break', Value: undefined, Target: undefined });
|
||||
}
|
||||
// 1. Let label be the StringValue of LabelIdentifier.
|
||||
const label = StringValue(LabelIdentifier);
|
||||
// 2. Return Completion { [[Type]]: break, [[Value]]: empty, [[Target]]: label }.
|
||||
return new Completion({ Type: 'break', Value: undefined, Target: label });
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
import { JSStringSet } from '../helpers.mts';
|
||||
import type { ParseNode } from '../parser/ParseNode.mts';
|
||||
import { LabelledEvaluation } from './all.mts';
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-statement-semantics-runtime-semantics-evaluation */
|
||||
// BreakableStatement :
|
||||
// IterationStatement
|
||||
// SwitchStatement
|
||||
//
|
||||
// IterationStatement :
|
||||
// (DoStatement)
|
||||
// (WhileStatement)
|
||||
export function Evaluate_BreakableStatement(BreakableStatement: ParseNode.BreakableStatement) {
|
||||
// 1. Let newLabelSet be a new empty List.
|
||||
const newLabelSet = new JSStringSet();
|
||||
// 2. Return the result of performing LabelledEvaluation of this BreakableStatement with argument newLabelSet.
|
||||
return LabelledEvaluation(BreakableStatement, newLabelSet);
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
import { surroundingAgent } from '../host-defined/engine.mts';
|
||||
import { Value, ReferenceRecord, JSStringValue } from '../value.mts';
|
||||
import { IsInTailPosition } from '../static-semantics/all.mts';
|
||||
import { Q } from '../completion.mts';
|
||||
import { Evaluate, type ValueEvaluator } from '../evaluator.mts';
|
||||
import type { ParseNode } from '../parser/ParseNode.mts';
|
||||
import { EvaluateCall, ArgumentListEvaluation } from './all.mts';
|
||||
import {
|
||||
GetValue,
|
||||
IsPropertyReference,
|
||||
PerformEval,
|
||||
SameValue,
|
||||
} from '#self';
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-function-calls-runtime-semantics-evaluation */
|
||||
// CallExpression :
|
||||
// CoverCallExpressionAndAsyncArrowHead
|
||||
// CallExpression Arguments
|
||||
export function* Evaluate_CallExpression(CallExpression: ParseNode.CallExpression): ValueEvaluator {
|
||||
// 1. Let expr be CoveredCallExpression of CoverCallExpressionAndAsyncArrowHead.
|
||||
const expr = CallExpression;
|
||||
// 2. Let memberExpr be the MemberExpression of expr.
|
||||
const memberExpr = expr.CallExpression;
|
||||
// 3. Let arguments be the Arguments of expr.
|
||||
const args = expr.Arguments;
|
||||
// 4. Let ref be the result of evaluating memberExpr.
|
||||
const ref = Q(yield* Evaluate(memberExpr));
|
||||
// 5. Let func be ? GetValue(ref).
|
||||
const func = Q(yield* GetValue(ref));
|
||||
// 6. If Type(ref) is Reference, IsPropertyReference(ref) is false, and GetReferencedName(ref) is "eval", then
|
||||
if (ref instanceof ReferenceRecord
|
||||
&& IsPropertyReference(ref) === Value.false
|
||||
&& (ref.ReferencedName instanceof JSStringValue
|
||||
&& ref.ReferencedName.stringValue() === 'eval')) {
|
||||
// a. If SameValue(func, %eval%) is true, then
|
||||
if (SameValue(func, surroundingAgent.intrinsic('%eval%')) === Value.true) {
|
||||
// i. Let argList be ? ArgumentListEvaluation of arguments.
|
||||
const argList = Q(yield* ArgumentListEvaluation(args));
|
||||
// ii. If argList has no elements, return undefined.
|
||||
if (argList.length === 0) {
|
||||
return Value.undefined;
|
||||
}
|
||||
// iii. Let evalText be the first element of argList.
|
||||
const evalText = argList[0]!;
|
||||
// iv. If the source code matching this CallExpression is strict mode code, let strictCaller be true. Otherwise let strictCaller be false.
|
||||
const strictCaller = CallExpression.strict;
|
||||
// vi. Return ? PerformEval(evalText, strictCaller, true).
|
||||
return Q(yield* PerformEval(evalText, strictCaller, true));
|
||||
}
|
||||
}
|
||||
// 7. Let thisCall be this CallExpression.
|
||||
const thisCall = CallExpression;
|
||||
// 8. Let tailCall be IsInTailPosition(thisCall).
|
||||
const tailCall = IsInTailPosition(thisCall);
|
||||
// 9. Return ? EvaluateCall(func, ref, arguments, tailCall).
|
||||
return Q(yield* EvaluateCall(func, ref, args, tailCall));
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
import { surroundingAgent } from '../host-defined/engine.mts';
|
||||
import { Value } from '../value.mts';
|
||||
import { StringValue } from '../static-semantics/all.mts';
|
||||
import { Q, NormalCompletion } from '../completion.mts';
|
||||
import type { ParseNode } from '../parser/ParseNode.mts';
|
||||
import type { PlainEvaluator, ValueEvaluator } from '../evaluator.mts';
|
||||
import {
|
||||
InitializeBoundName, ClassDefinitionEvaluation, type DecoratorDefinitionRecord, DecoratorListEvaluation,
|
||||
} from './all.mts';
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-runtime-semantics-bindingclassdeclarationevaluation */
|
||||
// ClassDeclaration :
|
||||
// `class` BindingIdentifier ClassTail
|
||||
// `class` ClassTail
|
||||
export function* BindingClassDeclarationEvaluation(ClassDeclaration: ParseNode.ClassDeclaration, decorators: readonly DecoratorDefinitionRecord[]): ValueEvaluator {
|
||||
const { BindingIdentifier, ClassTail } = ClassDeclaration;
|
||||
const sourceText = ClassDeclaration.sourceText;
|
||||
if (!BindingIdentifier) {
|
||||
return Q(yield* ClassDefinitionEvaluation(ClassTail, Value.undefined, Value('default'), sourceText, decorators));
|
||||
}
|
||||
// 1. Let className be StringValue of BindingIdentifier.
|
||||
const className = StringValue(BindingIdentifier);
|
||||
// 2. Let value be ? ClassDefinitionEvaluation of ClassTail with arguments className, className, decorators.
|
||||
const value = Q(yield* ClassDefinitionEvaluation(ClassTail, className, className, sourceText, decorators));
|
||||
// 4. Let env be the running execution context's LexicalEnvironment.
|
||||
const env = surroundingAgent.runningExecutionContext.LexicalEnvironment;
|
||||
// 5. Perform ? InitializeBoundName(className, value, env).
|
||||
Q(yield* InitializeBoundName(className, value, env));
|
||||
// 6. Return value.
|
||||
return value;
|
||||
}
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-class-definitions-runtime-semantics-evaluation */
|
||||
// ClassDeclaration : `class` BindingIdentifier ClassTAil
|
||||
export function* Evaluate_ClassDeclaration(ClassDeclaration: ParseNode.ClassDeclaration): PlainEvaluator {
|
||||
const decorators = ClassDeclaration.Decorators ? Q(yield* DecoratorListEvaluation(ClassDeclaration.Decorators)) : [];
|
||||
// 1. Perform ? BindingClassDeclarationEvaluation of this ClassDeclaration.
|
||||
Q(yield* BindingClassDeclarationEvaluation(ClassDeclaration, decorators));
|
||||
// 2. Return NormalCompletion(empty).
|
||||
return NormalCompletion(undefined);
|
||||
}
|
||||
@@ -0,0 +1,805 @@
|
||||
import { surroundingAgent } from '../host-defined/engine.mts';
|
||||
import {
|
||||
Value, NullValue, ObjectValue, PrivateName,
|
||||
BooleanValue,
|
||||
JSStringValue,
|
||||
type Arguments,
|
||||
type FunctionCallContext,
|
||||
UndefinedValue,
|
||||
type PropertyKeyValue,
|
||||
ReferenceRecord,
|
||||
SymbolValue,
|
||||
} from '../value.mts';
|
||||
import { Evaluate, type PlainEvaluator, type ValueEvaluator } from '../evaluator.mts';
|
||||
import {
|
||||
IsStatic,
|
||||
ConstructorMethod,
|
||||
NonConstructorElements,
|
||||
PrivateBoundIdentifiers,
|
||||
} from '../static-semantics/all.mts';
|
||||
import {
|
||||
Q, X,
|
||||
AbruptCompletion,
|
||||
} from '../completion.mts';
|
||||
import { __ts_cast__, OutOfRange, type Mutable } from '../helpers.mts';
|
||||
import type { ParseNode } from '../parser/ParseNode.mts';
|
||||
import {
|
||||
DefineMethod,
|
||||
MethodDefinitionEvaluation,
|
||||
ClassFieldDefinitionEvaluation,
|
||||
PrivateElementRecord,
|
||||
ClassFieldDefinitionRecord,
|
||||
ClassStaticBlockDefinitionEvaluation,
|
||||
ClassStaticBlockDefinitionRecord,
|
||||
ClassFieldDefinitionEvaluation_decorator,
|
||||
} from './all.mts';
|
||||
import {
|
||||
Assert,
|
||||
Call,
|
||||
Construct,
|
||||
CreateBuiltinFunction,
|
||||
Get,
|
||||
GetValue,
|
||||
IsConstructor,
|
||||
MakeConstructor,
|
||||
MakeClassConstructor,
|
||||
SetFunctionName,
|
||||
CreateMethodProperty,
|
||||
OrdinaryObjectCreate,
|
||||
OrdinaryCreateFromConstructor,
|
||||
PrivateMethodOrAccessorAdd,
|
||||
InitializeInstanceElements,
|
||||
DefineField,
|
||||
type ECMAScriptFunctionObject,
|
||||
type BuiltinFunctionObject,
|
||||
type FunctionObject,
|
||||
DefineMethodProperty,
|
||||
IsCallable,
|
||||
} from '#self';
|
||||
import {
|
||||
DeclarativeEnvironmentRecord,
|
||||
PrivateEnvironmentRecord,
|
||||
|
||||
CreateDataPropertyOrThrow, HasProperty, InitializeFieldOrAccessor, InitializePrivateMethods, IsPropertyKey, markBuiltinFunctionAsConstructor, PrivateElementFind, PrivateGet, PrivateSet, Set, Throw,
|
||||
} from '#self';
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-static-semantics-classelementevaluation */
|
||||
// -decorator
|
||||
function ClassElementEvaluation(node: ParseNode.MethodDefinition | ParseNode.GeneratorMethod | ParseNode.AsyncMethod | ParseNode.AsyncGeneratorMethod | ParseNode.FieldDefinition | ParseNode.ClassStaticBlock, object: ObjectValue, enumerable: BooleanValue): PlainEvaluator<PrivateElementRecord | ClassFieldDefinitionRecord | void>
|
||||
// +decorator
|
||||
function ClassElementEvaluation(node: ParseNode.MethodDefinition | ParseNode.GeneratorMethod | ParseNode.AsyncMethod | ParseNode.AsyncGeneratorMethod | ParseNode.FieldDefinition | ParseNode.ClassStaticBlock, object: ObjectValue): PlainEvaluator<ClassElementDefinitionRecord | ClassStaticBlockDefinitionRecord | void>
|
||||
function* ClassElementEvaluation(node: ParseNode.MethodDefinition | ParseNode.GeneratorMethod | ParseNode.AsyncMethod | ParseNode.AsyncGeneratorMethod | ParseNode.FieldDefinition | ParseNode.ClassStaticBlock, object: ObjectValue, enumerable?: BooleanValue): PlainEvaluator<ClassElementDefinitionRecord | ClassFieldDefinitionRecord | ClassStaticBlockDefinitionRecord | PrivateElementRecord | void> {
|
||||
switch (node.type) {
|
||||
case 'MethodDefinition':
|
||||
case 'GeneratorMethod':
|
||||
case 'AsyncMethod':
|
||||
case 'AsyncGeneratorMethod': {
|
||||
if (surroundingAgent.feature('decorators')) {
|
||||
const decorators = node.Decorators ? Q(yield* DecoratorListEvaluation(node.Decorators)) : [];
|
||||
const methodDefinition = Q(yield* MethodDefinitionEvaluation(node, object));
|
||||
methodDefinition.Decorators = decorators;
|
||||
return methodDefinition;
|
||||
} else {
|
||||
return yield* MethodDefinitionEvaluation(node, object, enumerable!);
|
||||
}
|
||||
}
|
||||
case 'FieldDefinition': {
|
||||
if (surroundingAgent.feature('decorators')) {
|
||||
const decorators = node.Decorators ? Q(yield* DecoratorListEvaluation(node.Decorators)) : [];
|
||||
const fieldDefinition = Q(yield* ClassFieldDefinitionEvaluation_decorator(node, object));
|
||||
fieldDefinition.Decorators = decorators;
|
||||
return fieldDefinition;
|
||||
} else {
|
||||
return yield* ClassFieldDefinitionEvaluation(node, object);
|
||||
}
|
||||
}
|
||||
case 'ClassStaticBlock':
|
||||
return ClassStaticBlockDefinitionEvaluation(node, object);
|
||||
default:
|
||||
throw new OutOfRange('ClassElementEvaluation', node);
|
||||
}
|
||||
}
|
||||
|
||||
export interface DefaultConstructorBuiltinFunction extends BuiltinFunctionObject {
|
||||
// -decorator
|
||||
readonly PrivateMethods: ECMAScriptFunctionObject['PrivateMethods'];
|
||||
readonly Fields: ECMAScriptFunctionObject['Fields'];
|
||||
// +decorator (PrivateMethods => Initializers, Fields => Elements)
|
||||
readonly Initializers: ECMAScriptFunctionObject['Initializers'];
|
||||
readonly Elements: ECMAScriptFunctionObject['Elements'];
|
||||
readonly SourceText: ECMAScriptFunctionObject['SourceText'];
|
||||
readonly ConstructorKind: ECMAScriptFunctionObject['ConstructorKind'];
|
||||
/**
|
||||
* Note: this is different than InitialName, which is used and observable in Function.prototype.toString.
|
||||
* This is only used in the inspector.
|
||||
*/
|
||||
readonly HostInitialName: PropertyKeyValue | PrivateName;
|
||||
}
|
||||
|
||||
// ClassTail : ClassHeritage? `{` ClassBody? `}`
|
||||
/** https://tc39.es/ecma262/#sec-runtime-semantics-classdefinitionevaluation */
|
||||
/** https://arai-a.github.io/ecma262-compare/snapshot.html?pr=2417#sec-runtime-semantics-classdefinitionevaluation */
|
||||
export function* ClassDefinitionEvaluation(ClassTail: ParseNode.ClassTail, classBinding: JSStringValue | UndefinedValue, className: PropertyKeyValue | PrivateName, sourceText: string, decorators: readonly DecoratorDefinitionRecord[]): ValueEvaluator<FunctionObject> {
|
||||
const { ClassHeritage, ClassBody } = ClassTail;
|
||||
// 1. Let env be the LexicalEnvironment of the running execution context.
|
||||
const env = surroundingAgent.runningExecutionContext.LexicalEnvironment;
|
||||
// 2. Let classScope be NewDeclarativeEnvironment(env).
|
||||
const classScope = new DeclarativeEnvironmentRecord(env);
|
||||
// 3. If classBinding is not undefined, then
|
||||
if (!(classBinding instanceof UndefinedValue)) {
|
||||
// a. Perform classScopeEnv.CreateImmutableBinding(classBinding, true).
|
||||
classScope.CreateImmutableBinding(classBinding, Value.true);
|
||||
}
|
||||
// 4. Let outerPrivateEnvironment be the running execution context's PrivateEnvironment.
|
||||
const outerPrivateEnvironment = surroundingAgent.runningExecutionContext.PrivateEnvironment;
|
||||
// 5. Let classPrivateEnvironment be NewPrivateEnvironment(outerPrivateEnvironment).
|
||||
const classPrivateEnvironment = new PrivateEnvironmentRecord(outerPrivateEnvironment);
|
||||
// 6. If ClassBody is present, then
|
||||
if (ClassBody) {
|
||||
// a. For each String dn of the PrivateBoundIdentifiers of ClassBody, do
|
||||
for (const dn of PrivateBoundIdentifiers(ClassBody)) {
|
||||
// i. If classPrivateEnvironment.[[Names]] contains a Private Name whose [[Description]] is dn, then
|
||||
const existing = classPrivateEnvironment.Names.find((n) => n.Description.stringValue() === dn.stringValue());
|
||||
if (existing) {
|
||||
// 1. Assert: This is only possible for getter/setter pairs.
|
||||
} else { // ii. Else,
|
||||
// 1. Let name be a new Private Name whose [[Description]] value is dn.
|
||||
const name = new PrivateName(dn);
|
||||
// 2. Append name to classPrivateEnvironment.[[Names]].
|
||||
classPrivateEnvironment.Names.push(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
let protoParent;
|
||||
let constructorParent: ObjectValue;
|
||||
// 7. If ClassHeritage is not present, then
|
||||
if (!ClassHeritage) {
|
||||
// a. Let protoParent be %Object.prototype%.
|
||||
protoParent = surroundingAgent.intrinsic('%Object.prototype%');
|
||||
// b. Let constructorParent be %Function.prototype%.
|
||||
constructorParent = surroundingAgent.intrinsic('%Function.prototype%');
|
||||
} else { // 8. Else,
|
||||
// a. Set the running execution context's LexicalEnvironment to classScope.
|
||||
surroundingAgent.runningExecutionContext.LexicalEnvironment = classScope;
|
||||
// b. Let superclassRef be the result of evaluating ClassHeritage.
|
||||
const superclassRef = Q(yield* Evaluate(ClassHeritage));
|
||||
// c. Set the running execution context's LexicalEnvironment to env.
|
||||
surroundingAgent.runningExecutionContext.LexicalEnvironment = env;
|
||||
// d. Let superclass be ? GetValue(superclassRef).
|
||||
const superclass = Q(yield* GetValue(superclassRef));
|
||||
// e. If superclass is null, then
|
||||
if (superclass instanceof NullValue) {
|
||||
// i. Let protoParent be null.
|
||||
protoParent = Value.null;
|
||||
// ii. Let constructorParent be %Function.prototype%.
|
||||
constructorParent = surroundingAgent.intrinsic('%Function.prototype%');
|
||||
} else if (!IsConstructor(superclass)) {
|
||||
// f. Else if IsConstructor(superclass) is false, throw a TypeError exception.
|
||||
return surroundingAgent.Throw('TypeError', 'NotAConstructor', superclass);
|
||||
} else { // g. Else,
|
||||
// i. Let protoParent be ? Get(superclass, "prototype").
|
||||
protoParent = Q(yield* Get(superclass as ObjectValue, Value('prototype')));
|
||||
// ii. If Type(protoParent) is neither Object nor Null, throw a TypeError exception.
|
||||
if (!(protoParent instanceof ObjectValue) && !(protoParent instanceof NullValue)) {
|
||||
return surroundingAgent.Throw('TypeError', 'ObjectPrototypeType');
|
||||
}
|
||||
// iii. Let constructorParent be superclass.
|
||||
constructorParent = superclass as ObjectValue;
|
||||
}
|
||||
}
|
||||
// 9. Let proto be OrdinaryObjectCreate(protoParent).
|
||||
const proto = OrdinaryObjectCreate(protoParent);
|
||||
let constructor;
|
||||
// 10. If ClassBody is not present, let constructor be empty.
|
||||
if (!ClassBody) {
|
||||
constructor = undefined;
|
||||
} else { // 11. Else, let constructor be ConstructorMethod of ClassBody.
|
||||
constructor = ConstructorMethod(ClassBody);
|
||||
}
|
||||
// 12. Set the running execution context's LexicalEnvironment to classScope.
|
||||
surroundingAgent.runningExecutionContext.LexicalEnvironment = classScope;
|
||||
// 13. Set the running execution context's PrivateEnvironment to classPrivateEnvironment.
|
||||
surroundingAgent.runningExecutionContext.PrivateEnvironment = classPrivateEnvironment;
|
||||
let F;
|
||||
// 14. If constructor is empty, then
|
||||
if (constructor === undefined) {
|
||||
// a. Let defaultConstructor be a new Abstract Closure with no parameters that captures nothing and performs the following steps when called:
|
||||
const defaultConstructor = function* defaultConstructor(args: Arguments, { NewTarget }: FunctionCallContext) {
|
||||
// i. Let args be the List of arguments that was passed to this function by [[Call]] or [[Construct]].
|
||||
// ii. If NewTarget is undefined, throw a TypeError exception.
|
||||
if (NewTarget instanceof UndefinedValue) {
|
||||
return surroundingAgent.Throw('TypeError', 'ConstructorNonCallable', surroundingAgent.activeFunctionObject);
|
||||
}
|
||||
// iii. Let F be the active function object.
|
||||
const F = surroundingAgent.activeFunctionObject as ECMAScriptFunctionObject; // eslint-disable-line no-shadow
|
||||
let result;
|
||||
// iv. If F.[[ConstructorKind]] is derived, then
|
||||
if (F.ConstructorKind === 'derived') {
|
||||
// 1. NOTE: This branch behaves similarly to `constructor(...args) { super(...args); }`. The most
|
||||
// notable distinction is that while the aforementioned ECMAScript source text observably calls
|
||||
// the @@iterator method on `%Array.prototype%`, a Default Constructor Function does not.
|
||||
// 2. Let func be ! F.[[GetPrototypeOf]]().
|
||||
const func = X(yield* F.GetPrototypeOf());
|
||||
// 3. If IsConstructor(func) is false, throw a TypeError exception.
|
||||
if (!IsConstructor(func)) {
|
||||
return surroundingAgent.Throw('TypeError', 'NotAConstructor', func);
|
||||
}
|
||||
// 4. Let result be ? Construct(func, args, NewTarget).
|
||||
result = Q(yield* Construct(func, args, NewTarget));
|
||||
} else { // v. Else,
|
||||
// 1. NOTE: This branch behaves similarly to `constructor() {}`.
|
||||
// 2. Let result be ? OrdinaryCreateFromConstructor(NewTarget, "%Object.prototype%").
|
||||
result = Q(yield* OrdinaryCreateFromConstructor(NewTarget, '%Object.prototype%'));
|
||||
}
|
||||
Q(yield* InitializeInstanceElements(result, F));
|
||||
return result;
|
||||
};
|
||||
// b. ! CreateBuiltinFunction(defaultConstructor, 0, className, « [[ConstructorKind]], [[SourceText]], [[PrivateMethods]], [[Fields]] », the current Realm Record, constructorParent).
|
||||
F = X(CreateBuiltinFunction(markBuiltinFunctionAsConstructor(defaultConstructor), 0, className, ['ConstructorKind', 'SourceText', surroundingAgent.feature('decorators') ? 'Initializers' : 'PrivateMethods', surroundingAgent.feature('decorators') ? 'Elements' : 'Fields'], surroundingAgent.currentRealmRecord, constructorParent));
|
||||
} else { // 15. Else,
|
||||
// a. Let constructorInfo be ! DefineMethod of constructor with arguments proto and constructorParent.
|
||||
const constructorInfo = X(yield* DefineMethod(constructor, proto, constructorParent));
|
||||
// b. Let F be constructorInfo.[[Closure]].
|
||||
F = constructorInfo.Closure;
|
||||
// c. Perform SetFunctionName(F, className).
|
||||
SetFunctionName(F, className);
|
||||
}
|
||||
__ts_cast__<Mutable<DefaultConstructorBuiltinFunction>>(F);
|
||||
F.HostInitialName = className;
|
||||
F.SourceText = sourceText;
|
||||
// 16. Perform MakeConstructor(F, false, proto).
|
||||
MakeConstructor(F, Value.false, proto);
|
||||
// https://github.com/tc39/ecma262/pull/3212/
|
||||
// 17. Perform MakeClassConstructor(F).
|
||||
MakeClassConstructor(F);
|
||||
// 18. If ClassHeritage is present, set F.[[ConstructorKind]] to derived.
|
||||
if (ClassHeritage) {
|
||||
F.ConstructorKind = 'derived';
|
||||
}
|
||||
// 19. Perform CreateMethodProperty(proto, "constructor", F).
|
||||
X(CreateMethodProperty(proto, Value('constructor'), F));
|
||||
// 20. If ClassBody is not present, let elements be a new empty List.
|
||||
let elements: ParseNode.ClassElement[];
|
||||
if (!ClassBody) {
|
||||
elements = [];
|
||||
} else { // 20. Else, let elements be NonConstructorElements of ClassBody.
|
||||
elements = NonConstructorElements(ClassBody);
|
||||
}
|
||||
if (surroundingAgent.feature('decorators')) {
|
||||
const instanceElements: ClassElementDefinitionRecord[] = [];
|
||||
// 24. Let staticElements be a new empty List.
|
||||
const staticElements: (ClassElementDefinitionRecord | ClassStaticBlockDefinitionRecord)[] = [];
|
||||
// 25. For each ClassElement e of elements, do
|
||||
for (const e of elements) {
|
||||
let result;
|
||||
// a. If IsStatic of e is false, then
|
||||
if (!IsStatic(e)) {
|
||||
result = yield* ClassElementEvaluation(e, proto);
|
||||
} else {
|
||||
result = yield* ClassElementEvaluation(e, F);
|
||||
}
|
||||
// c. If field is an abrupt completion, then
|
||||
if (result instanceof AbruptCompletion) {
|
||||
// i. Set the running execution context's LexicalEnvironment to env.
|
||||
surroundingAgent.runningExecutionContext.LexicalEnvironment = env;
|
||||
// ii. Set the running execution context's PrivateEnvironment to outerPrivateEnvironment.
|
||||
surroundingAgent.runningExecutionContext.PrivateEnvironment = outerPrivateEnvironment;
|
||||
return result;
|
||||
}
|
||||
const element = X(result);
|
||||
if (element instanceof ClassElementDefinitionRecord) {
|
||||
if (!IsStatic(e)) {
|
||||
instanceElements.push(element);
|
||||
} else {
|
||||
staticElements.push(element);
|
||||
}
|
||||
} else {
|
||||
Assert(element instanceof ClassStaticBlockDefinitionRecord);
|
||||
staticElements.push(element);
|
||||
}
|
||||
}
|
||||
// 26. Set the running execution context's LexicalEnvironment to env.
|
||||
surroundingAgent.runningExecutionContext.LexicalEnvironment = env;
|
||||
const instanceMethodExtraInitializers: FunctionObject[] = [];
|
||||
const staticMethodExtraInitializers: FunctionObject[] = [];
|
||||
for (const e of staticElements) {
|
||||
if (e instanceof ClassElementDefinitionRecord && e.Kind !== 'field') {
|
||||
let extraInitializers: FunctionObject[];
|
||||
if (e.Kind === 'accessor') {
|
||||
extraInitializers = e.ExtraInitializers;
|
||||
} else {
|
||||
extraInitializers = staticMethodExtraInitializers;
|
||||
}
|
||||
const result = yield* ApplyDecoratorsAndDefineMethod(F, e, extraInitializers, true);
|
||||
if (result instanceof AbruptCompletion) {
|
||||
surroundingAgent.runningExecutionContext.PrivateEnvironment = outerPrivateEnvironment;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (const e of instanceElements) {
|
||||
let extraInitializers: FunctionObject[];
|
||||
if (e.Kind !== 'field') {
|
||||
if (e.Kind === 'accessor') {
|
||||
extraInitializers = e.ExtraInitializers;
|
||||
} else {
|
||||
extraInitializers = instanceMethodExtraInitializers;
|
||||
}
|
||||
const result = yield* ApplyDecoratorsAndDefineMethod(proto, e, extraInitializers, false);
|
||||
if (result instanceof AbruptCompletion) {
|
||||
surroundingAgent.runningExecutionContext.PrivateEnvironment = outerPrivateEnvironment;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (const e of staticElements) {
|
||||
if (e instanceof ClassElementDefinitionRecord && e.Kind === 'field') {
|
||||
const result = yield* ApplyDecoratorsToElementDefinition(F, e, e.ExtraInitializers, true);
|
||||
if (result instanceof AbruptCompletion) {
|
||||
surroundingAgent.runningExecutionContext.PrivateEnvironment = outerPrivateEnvironment;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (const e of instanceElements) {
|
||||
if (e.Kind === 'field') {
|
||||
const result = yield* ApplyDecoratorsToElementDefinition(proto, e, e.ExtraInitializers, false);
|
||||
if (result instanceof AbruptCompletion) {
|
||||
surroundingAgent.runningExecutionContext.PrivateEnvironment = outerPrivateEnvironment;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
F.Elements = instanceElements;
|
||||
F.Initializers = instanceMethodExtraInitializers;
|
||||
// TODO(decorator): spec bug?
|
||||
// Q(yield* InitializePrivateMethods(F, staticElements));
|
||||
Q(yield* InitializePrivateMethods(F, staticElements.filter((element): element is ClassElementDefinitionRecord => element instanceof ClassElementDefinitionRecord)));
|
||||
const classExtraInitializers: FunctionObject[] = [];
|
||||
const newF = yield* ApplyDecoratorsToClassDefinition(F, decorators, className, classExtraInitializers);
|
||||
if (newF instanceof AbruptCompletion) {
|
||||
surroundingAgent.runningExecutionContext.PrivateEnvironment = outerPrivateEnvironment;
|
||||
return newF;
|
||||
}
|
||||
F = Q(newF);
|
||||
// 27. If classBinding is not undefined, then
|
||||
if (!(classBinding instanceof UndefinedValue)) {
|
||||
// a. Perform classScope.InitializeBinding(classBinding, F).
|
||||
yield* classScope.InitializeBinding(classBinding, F);
|
||||
}
|
||||
for (const initializer of staticMethodExtraInitializers) {
|
||||
const result = yield* Call(initializer, F);
|
||||
if (result instanceof AbruptCompletion) {
|
||||
surroundingAgent.runningExecutionContext.PrivateEnvironment = outerPrivateEnvironment;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
// 31. For each element elementRecord of staticElements, do
|
||||
for (const elementRecord of staticElements) {
|
||||
let result;
|
||||
// a. If elementRecord is a ClassFieldDefinition Record, then
|
||||
if (elementRecord instanceof ClassElementDefinitionRecord && (elementRecord.Kind === 'field' || elementRecord.Kind === 'accessor')) {
|
||||
// a. Let result be DefineField(F, elementRecord).
|
||||
result = yield* InitializeFieldOrAccessor(F, elementRecord);
|
||||
} else if (elementRecord instanceof ClassStaticBlockDefinitionRecord) {
|
||||
result = yield* Call(elementRecord.BodyFunction, F);
|
||||
}
|
||||
// c. If result is an abrupt completion, then
|
||||
if (result instanceof AbruptCompletion) {
|
||||
// i. Set the running execution context's PrivateEnvironment to outerPrivateEnvironment.
|
||||
surroundingAgent.runningExecutionContext.PrivateEnvironment = outerPrivateEnvironment;
|
||||
// ii. Return result.
|
||||
return result;
|
||||
}
|
||||
}
|
||||
for (const initializer of classExtraInitializers) {
|
||||
const result = yield* Call(initializer, F);
|
||||
if (result instanceof AbruptCompletion) {
|
||||
surroundingAgent.runningExecutionContext.PrivateEnvironment = outerPrivateEnvironment;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
// 32. Set the running execution context's PrivateEnvironment to outerPrivateEnvironment.
|
||||
surroundingAgent.runningExecutionContext.PrivateEnvironment = outerPrivateEnvironment;
|
||||
// 33. Return F.
|
||||
return F;
|
||||
} else {
|
||||
// 21. Let instancePrivateMethods be a new empty List.
|
||||
const instancePrivateMethods: never[] = [];
|
||||
// 22. Let staticPrivateMethods be a new empty List.
|
||||
const staticPrivateMethods: never[] = [];
|
||||
// 23. Let instanceFields be a new empty List.
|
||||
const instanceFields: ClassFieldDefinitionRecord[] = [];
|
||||
// 24. Let staticElements be a new empty List.
|
||||
const staticElements: (ClassFieldDefinitionRecord | ClassStaticBlockDefinitionRecord)[] = [];
|
||||
// 25. For each ClassElement e of elements, do
|
||||
for (const e of elements) {
|
||||
let field;
|
||||
// a. If IsStatic of e is false, then
|
||||
if (IsStatic(e) === false) {
|
||||
// i. Let field be ClassElementEvaluation of e with arguments proto and false.
|
||||
field = (yield* ClassElementEvaluation(e, proto, Value.false))!;
|
||||
} else { // b. Else,
|
||||
// i. Let field be ClassElementEvaluation of e with arguments F and false.
|
||||
field = (yield* ClassElementEvaluation(e, F, Value.false))!;
|
||||
}
|
||||
// c. If field is an abrupt completion, then
|
||||
if (field instanceof AbruptCompletion) {
|
||||
// i. Set the running execution context's LexicalEnvironment to env.
|
||||
surroundingAgent.runningExecutionContext.LexicalEnvironment = env;
|
||||
// ii. Set the running execution context's PrivateEnvironment to outerPrivateEnvironment.
|
||||
surroundingAgent.runningExecutionContext.PrivateEnvironment = outerPrivateEnvironment;
|
||||
// iii. Return Completion(field).
|
||||
return field;
|
||||
}
|
||||
// d. Set field to field.[[Value]].
|
||||
Q(field);
|
||||
// e. If field is a PrivateElement, then
|
||||
if (field instanceof PrivateElementRecord) {
|
||||
// i. Assert: field.[[Kind]] is either method or accessor.
|
||||
Assert(field.Kind === 'method' || field.Kind === 'accessor');
|
||||
// ii. If IsStatic of e is false, let container be instancePrivateMethods.
|
||||
let container: PrivateElementRecord[];
|
||||
if (IsStatic(e) === false) {
|
||||
container = instancePrivateMethods;
|
||||
} else { // iii. Else, let container be staticPrivateMethods.
|
||||
container = staticPrivateMethods;
|
||||
}
|
||||
// iv. If container contains a PrivateElement whose [[Key]] is field.[[Key]], then
|
||||
const index = container.findIndex((el) => el.Key === field.Key);
|
||||
if (index >= 0) {
|
||||
// 1. Let existing be that PrivateElement.
|
||||
const existing = container[index];
|
||||
// 2. Assert: field.[[Kind]] and existing.[[Kind]] are both accessor.
|
||||
Assert(field.Kind === 'accessor' && existing.Kind === 'accessor');
|
||||
// 3. If field.[[Get]] is undefined, then
|
||||
let combined;
|
||||
if (field.Get === Value.undefined) {
|
||||
combined = PrivateElementRecord({
|
||||
Key: field.Key,
|
||||
Kind: 'accessor',
|
||||
Get: existing.Get,
|
||||
Set: field.Set,
|
||||
});
|
||||
} else { // 4. Else
|
||||
combined = PrivateElementRecord({
|
||||
Key: field.Key,
|
||||
Kind: 'accessor',
|
||||
Get: field.Get,
|
||||
Set: existing.Set,
|
||||
});
|
||||
}
|
||||
// 5. Replace existing in container with combined.
|
||||
container[index] = combined;
|
||||
} else { // v. Else,
|
||||
// 1. Append field to container.
|
||||
container.push(field);
|
||||
}
|
||||
} else if (field instanceof ClassFieldDefinitionRecord) { // f. Else if field is a ClassFieldDefinition Record, then
|
||||
// i. If IsStatic of e is false, append field to instanceFields.
|
||||
if (IsStatic(e) === false) {
|
||||
instanceFields.push(field);
|
||||
} else { // ii. Else, append field to staticElements.
|
||||
staticElements.push(field);
|
||||
}
|
||||
} else if (field instanceof ClassStaticBlockDefinitionRecord) { // g. Else if element is a ClassStaticBlockDefinition Record, then
|
||||
// i. Append element to staticElements.
|
||||
staticElements.push(field);
|
||||
}
|
||||
}
|
||||
// 26. Set the running execution context's LexicalEnvironment to env.
|
||||
surroundingAgent.runningExecutionContext.LexicalEnvironment = env;
|
||||
// 27. If classBinding is not undefined, then
|
||||
if (!(classBinding instanceof UndefinedValue)) {
|
||||
// a. Perform classScope.InitializeBinding(classBinding, F).
|
||||
yield* classScope.InitializeBinding(classBinding, F);
|
||||
}
|
||||
// 28. Set F.[[PrivateMethods]] to instancePrivateMethods.
|
||||
F.PrivateMethods = instancePrivateMethods;
|
||||
// 29. Set F.[[Fields]] to instanceFields.
|
||||
F.Fields = instanceFields;
|
||||
// 30. For each PrivateElement method of staticPrivateMethods, do
|
||||
for (const method of staticPrivateMethods) {
|
||||
// a. Perform ! PrivateMethodOrAccessorAdd(F, method).
|
||||
Q(yield* PrivateMethodOrAccessorAdd(F, method));
|
||||
}
|
||||
// 31. For each element elementRecord of staticElements, do
|
||||
for (const elementRecord of staticElements) {
|
||||
let result;
|
||||
// a. If elementRecord is a ClassFieldDefinition Record, then
|
||||
if (elementRecord instanceof ClassFieldDefinitionRecord) {
|
||||
// a. Let result be DefineField(F, elementRecord).
|
||||
result = yield* DefineField(F, elementRecord);
|
||||
} else { // b. Else,
|
||||
// i. Assert: elementRecord is a ClassStaticBlockDefinition Record.
|
||||
Assert(elementRecord instanceof ClassStaticBlockDefinitionRecord);
|
||||
// ii. Let result be Completion(Call(elementRecord.[[BodyFunction]], F)).
|
||||
result = yield* Call(elementRecord.BodyFunction, F);
|
||||
}
|
||||
// c. If result is an abrupt completion, then
|
||||
if (result instanceof AbruptCompletion) {
|
||||
// i. Set the running execution context's PrivateEnvironment to outerPrivateEnvironment.
|
||||
surroundingAgent.runningExecutionContext.PrivateEnvironment = outerPrivateEnvironment;
|
||||
// ii. Return result.
|
||||
return result;
|
||||
}
|
||||
}
|
||||
// 32. Set the running execution context's PrivateEnvironment to outerPrivateEnvironment.
|
||||
surroundingAgent.runningExecutionContext.PrivateEnvironment = outerPrivateEnvironment;
|
||||
// 33. Return F.
|
||||
return F;
|
||||
}
|
||||
}
|
||||
|
||||
/** https://arai-a.github.io/ecma262-compare/snapshot.html?pr=2417#sec-decoratorevaluation */
|
||||
export function* DecoratorEvaluation(decorator: ParseNode.Decorator): PlainEvaluator<DecoratorDefinitionRecord> {
|
||||
const expr = decorator.MemberExpression || decorator.CallExpression || decorator.ParenthesizedExpression;
|
||||
const ref = Q(yield* Evaluate(expr));
|
||||
const value = Q(yield* GetValue(ref));
|
||||
return { Decorator: value, Receiver: ref };
|
||||
}
|
||||
|
||||
/** https://arai-a.github.io/ecma262-compare/snapshot.html?pr=2417#sec-decoratorelistvaluation */
|
||||
export function* DecoratorListEvaluation(decoratorList: readonly ParseNode.Decorator[]): PlainEvaluator<DecoratorDefinitionRecord[]> {
|
||||
const decorators: DecoratorDefinitionRecord[] = [];
|
||||
for (const decoratorNode of decoratorList) {
|
||||
const decoratorRecord = Q(yield* DecoratorEvaluation(decoratorNode));
|
||||
decorators.unshift(decoratorRecord);
|
||||
}
|
||||
return decorators;
|
||||
}
|
||||
|
||||
/** https://arai-a.github.io/ecma262-compare/snapshot.html?pr=2417#sec-createdecoratoraccessobject */
|
||||
export function CreateDecoratorAccessObject(kind: ClassElementDefinitionRecord['Kind'], name: PropertyKeyValue | PrivateName): ObjectValue {
|
||||
const accessObj = OrdinaryObjectCreate(surroundingAgent.intrinsic('%Object.prototype%'));
|
||||
if (kind === 'field' || kind === 'method' || kind === 'accessor' || kind === 'getter') {
|
||||
const getterClosure = function* getter([obj = Value.undefined]: Arguments) {
|
||||
if (!(obj instanceof ObjectValue)) {
|
||||
return Throw.TypeError('Invalid receiver');
|
||||
}
|
||||
if (IsPropertyKey(name)) {
|
||||
return Q(yield* Get(obj, name));
|
||||
} else {
|
||||
return Q(yield* PrivateGet(obj, name));
|
||||
}
|
||||
};
|
||||
const getter = CreateBuiltinFunction(getterClosure, 1, Value(''), []);
|
||||
X(CreateDataPropertyOrThrow(accessObj, Value('get'), getter));
|
||||
}
|
||||
if (kind === 'field' || kind === 'accessor' || kind === 'setter') {
|
||||
const setterClosure = function* setter([obj = Value.undefined, value = Value.undefined]: Arguments) {
|
||||
if (!(obj instanceof ObjectValue)) {
|
||||
return Throw.TypeError('Invalid receiver');
|
||||
}
|
||||
if (IsPropertyKey(name)) {
|
||||
return Q(yield* Set(obj, name, value, Value.true));
|
||||
} else {
|
||||
return Q(yield* PrivateSet(obj, name, value));
|
||||
}
|
||||
};
|
||||
const setter = CreateBuiltinFunction(setterClosure, 2, Value(''), []);
|
||||
X(CreateDataPropertyOrThrow(accessObj, Value('set'), setter));
|
||||
}
|
||||
const hasClosure = function* has(this: Value, [obj = Value.undefined]: Arguments) {
|
||||
if (!(obj instanceof ObjectValue)) {
|
||||
return Throw.TypeError('Invalid receiver');
|
||||
}
|
||||
if (IsPropertyKey(name)) {
|
||||
return Q(yield* HasProperty(obj, name));
|
||||
}
|
||||
if (PrivateElementFind(name, obj)) {
|
||||
return Value.true;
|
||||
}
|
||||
return Value.false;
|
||||
};
|
||||
const has = CreateBuiltinFunction(hasClosure, 1, Value('has'), []);
|
||||
X(CreateDataPropertyOrThrow(accessObj, Value('has'), has));
|
||||
return accessObj;
|
||||
}
|
||||
|
||||
/** https://arai-a.github.io/ecma262-compare/snapshot.html?pr=2417#sec-createaddinitializerfunction */
|
||||
// TODO(decorator): spec bug, initializers should not require ECMAScriptFunctionObject
|
||||
export function CreateAddInitializerFunction(initializers: FunctionObject[], decorationState: { Finished: boolean }): FunctionObject {
|
||||
const addInitializerClosure = function* addInitializer(this: Value, [initializer = Value.undefined]: Arguments) {
|
||||
if (decorationState.Finished) {
|
||||
return Throw.TypeError('Cannot call addInitializer after decoration is finished');
|
||||
}
|
||||
if (!IsCallable(initializer)) {
|
||||
return Throw.TypeError('addInitializer must be called with a function, but $1 was passed', initializer);
|
||||
}
|
||||
initializers.push(initializer);
|
||||
return Value.undefined;
|
||||
};
|
||||
return CreateBuiltinFunction(addInitializerClosure, 1, Value('addInitializer'), []);
|
||||
}
|
||||
|
||||
/** https://arai-a.github.io/ecma262-compare/snapshot.html?pr=2417#sec-createdecoratorcontextobject */
|
||||
export function CreateDecoratorContextObject(kind: 'class' | ClassElementDefinitionRecord['Kind'], name: PropertyKeyValue | PrivateName, initializers: FunctionObject[], decorationState: { Finished: boolean }, isStatic?: boolean): ObjectValue {
|
||||
const contextObj = OrdinaryObjectCreate(surroundingAgent.intrinsic('%Object.prototype%'));
|
||||
const kindStr = Value(kind);
|
||||
X(CreateDataPropertyOrThrow(contextObj, Value('kind'), kindStr));
|
||||
if (kind !== 'class') {
|
||||
X(CreateDataPropertyOrThrow(contextObj, Value('access'), CreateDecoratorAccessObject(kind, name)));
|
||||
if (isStatic !== undefined) {
|
||||
X(CreateDataPropertyOrThrow(contextObj, Value('static'), Value(isStatic)));
|
||||
}
|
||||
if (name instanceof PrivateName) {
|
||||
X(CreateDataPropertyOrThrow(contextObj, Value('private'), Value.true));
|
||||
X(CreateDataPropertyOrThrow(contextObj, Value('name'), name.Description));
|
||||
} else {
|
||||
X(CreateDataPropertyOrThrow(contextObj, Value('private'), Value.false));
|
||||
X(CreateDataPropertyOrThrow(contextObj, Value('name'), name));
|
||||
}
|
||||
} else {
|
||||
// TODO(decorator): spec bug, no assert to the name
|
||||
X(CreateDataPropertyOrThrow(contextObj, Value('name'), name as PropertyKeyValue));
|
||||
}
|
||||
const addInitializer = CreateAddInitializerFunction(initializers, decorationState);
|
||||
X(CreateDataPropertyOrThrow(contextObj, Value('addInitializer'), addInitializer));
|
||||
return contextObj;
|
||||
}
|
||||
|
||||
/** https://arai-a.github.io/ecma262-compare/snapshot.html?pr=2417#sec-applydecoratorstoelementdefinition */
|
||||
// TODO(decorator): unused parameter in the spec
|
||||
export function* ApplyDecoratorsToElementDefinition(_homeObject: ObjectValue, elementRecord: ClassElementDefinitionRecord, extraInitializers: FunctionObject[], isStatic: boolean): PlainEvaluator<void> {
|
||||
const decorators = elementRecord.Decorators;
|
||||
if (!decorators || decorators.length === 0) {
|
||||
return undefined;
|
||||
}
|
||||
const key = elementRecord.Key;
|
||||
const kind = elementRecord.Kind;
|
||||
for (const decoratorRecord of decorators) {
|
||||
const decorator = decoratorRecord.Decorator;
|
||||
const decoratorReceiver = decoratorRecord.Receiver;
|
||||
const decorationState = { Finished: false };
|
||||
const context = CreateDecoratorContextObject(kind, key, extraInitializers, decorationState, isStatic);
|
||||
let value: Value = Value.undefined;
|
||||
if (kind === 'method') {
|
||||
value = elementRecord.Value;
|
||||
} else if (kind === 'getter') {
|
||||
value = elementRecord.Get;
|
||||
} else if (kind === 'setter') {
|
||||
value = elementRecord.Set;
|
||||
} else if (kind === 'accessor') {
|
||||
value = OrdinaryObjectCreate(surroundingAgent.intrinsic('%Object.prototype%'));
|
||||
X(CreateDataPropertyOrThrow(value, Value('get'), elementRecord.Get));
|
||||
X(CreateDataPropertyOrThrow(value, Value('set'), elementRecord.Set));
|
||||
}
|
||||
// TODO(decorator): spec bug, missing GetValue call
|
||||
// const newValue = Q(yield* Call(decorator, decoratorReceiver), [value, context]));
|
||||
const newValue = Q(yield* Call(decorator, Q(yield* GetValue(decoratorReceiver)), [value, context]));
|
||||
decorationState.Finished = true;
|
||||
if (kind === 'field') {
|
||||
if (IsCallable(newValue)) {
|
||||
// TODO(decorator): spec bug. ApplyDecoratorsToElementDefinition unshift decorator initializers into this array, but read it in order, so the spec order is wrong (be like [decorator2, decorator1, syntaxInit], but the correct order should be [syntaxInit, decorator2, decorator1])
|
||||
elementRecord.Initializers.unshift(newValue);
|
||||
} else if (newValue !== Value.undefined) {
|
||||
return Throw.TypeError('Field decorator must return a function or undefined, but $1 was returned', newValue);
|
||||
}
|
||||
} else if (kind === 'accessor') {
|
||||
if (newValue instanceof ObjectValue) {
|
||||
const newGetter = Q(yield* Get(newValue, Value('get')));
|
||||
if (IsCallable(newGetter)) {
|
||||
elementRecord.Get = newGetter;
|
||||
} else if (newGetter !== Value.undefined) {
|
||||
return Throw.TypeError('The get property of the return value of an accessor decorator must be a function or undefined, but $1 was returned', newGetter);
|
||||
}
|
||||
const newSetter = Q(yield* Get(newValue, Value('set')));
|
||||
if (IsCallable(newSetter)) {
|
||||
elementRecord.Set = newSetter;
|
||||
} else if (newSetter !== Value.undefined) {
|
||||
return Throw.TypeError('The set property of the return value of an accessor decorator must be a function or undefined, but $1 was returned', newSetter);
|
||||
}
|
||||
const initializer = Q(yield* Get(newValue, Value('init')));
|
||||
if (IsCallable(initializer)) {
|
||||
// TODO(decorator): spec bug. ApplyDecoratorsToElementDefinition unshift decorator initializers into this array, but read it in order, so the spec order is wrong (be like [decorator2, decorator1, syntaxInit], but the correct order should be [syntaxInit, decorator2, decorator1])
|
||||
elementRecord.Initializers.unshift(initializer);
|
||||
} else if (initializer !== Value.undefined) {
|
||||
return Throw.TypeError('The init property of the return value of an accessor decorator must be a function or undefined, but $1 was returned', initializer);
|
||||
}
|
||||
} else if (newValue !== Value.undefined) {
|
||||
return Throw.TypeError('Accessor decorator must return an object or undefined, but $1 was returned', newValue);
|
||||
}
|
||||
} else {
|
||||
if (IsCallable(newValue)) {
|
||||
if (kind === 'getter') {
|
||||
elementRecord.Get = newValue;
|
||||
} else if (kind === 'setter') {
|
||||
elementRecord.Set = newValue;
|
||||
} else {
|
||||
elementRecord.Value = newValue;
|
||||
}
|
||||
} else if (newValue !== Value.undefined) {
|
||||
return Throw.TypeError('Method decorator must return a function or undefined, but $1 was returned', newValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
elementRecord.Decorators = undefined;
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/** https://arai-a.github.io/ecma262-compare/snapshot.html?pr=2417#sec-applydecoratorstoclassdefinition */
|
||||
export function* ApplyDecoratorsToClassDefinition(classDef: FunctionObject, decorators: readonly DecoratorDefinitionRecord[], className: PropertyKeyValue | PrivateName, extraInitializers: FunctionObject[]): PlainEvaluator<FunctionObject> {
|
||||
for (const decoratorRecord of decorators) {
|
||||
const decorator = decoratorRecord.Decorator;
|
||||
const decoratorReceiver = decoratorRecord.Receiver;
|
||||
const decorationState = { Finished: false };
|
||||
const context = CreateDecoratorContextObject('class', className, extraInitializers, decorationState);
|
||||
// TODO(decorator): spec bug, missing GetValue call
|
||||
// const newDef = Q(yield* Call(decorator, decoratorReceiver, [classDef, context]));
|
||||
const newDef = Q(yield* Call(decorator, Q(yield* GetValue(decoratorReceiver)), [classDef, context]));
|
||||
decorationState.Finished = true;
|
||||
if (IsCallable(newDef)) {
|
||||
classDef = newDef;
|
||||
} else if (newDef !== Value.undefined) {
|
||||
return Throw.TypeError('Class decorator must return a function or undefined, but $1 was returned', newDef);
|
||||
}
|
||||
}
|
||||
return classDef;
|
||||
}
|
||||
|
||||
/** https://arai-a.github.io/ecma262-compare/snapshot.html?pr=2417#sec-applydecoratorsanddefinemethod */
|
||||
export function* ApplyDecoratorsAndDefineMethod(homeObject: ObjectValue, methodDefinition: ClassElementDefinitionRecord, extraInitializers: FunctionObject[], isStatic: boolean): PlainEvaluator<void> {
|
||||
Q(yield* ApplyDecoratorsToElementDefinition(homeObject, methodDefinition, extraInitializers, isStatic));
|
||||
// TODO(decorator): spec bug, enumerable of class methods, whether decorated or not, should always be false
|
||||
// Q(yield* DefineMethodProperty(homeObject, methodDefinition, isStatic));
|
||||
Q(yield* DefineMethodProperty(homeObject, methodDefinition, false));
|
||||
}
|
||||
|
||||
/** https://arai-a.github.io/ecma262-compare/snapshot.html?pr=2417#sec-decoratordefinition-record-specification-type */
|
||||
export interface DecoratorDefinitionRecord {
|
||||
readonly Decorator: Value;
|
||||
readonly Receiver: ReferenceRecord | Value;
|
||||
}
|
||||
|
||||
/** https://arai-a.github.io/ecma262-compare/snapshot.html?pr=2417#sec-classfielddefinition-record-specification-type */
|
||||
export type ClassElementDefinitionRecord = ClassElementDefinitionRecord_Method | ClassElementDefinitionRecord_Field | ClassElementDefinitionRecord_Accessor | ClassElementDefinitionRecord_Getter | ClassElementDefinitionRecord_Setter;
|
||||
export interface ClassElementDefinitionRecord_Method {
|
||||
readonly Kind: 'method';
|
||||
readonly Key: PrivateName | JSStringValue | SymbolValue;
|
||||
// TODO(decorator): spec bug, spec is ECMAScriptFunctionObject
|
||||
Value: FunctionObject;
|
||||
Decorators: DecoratorDefinitionRecord[] | undefined;
|
||||
}
|
||||
export interface ClassElementDefinitionRecord_Field {
|
||||
readonly Kind: 'field';
|
||||
readonly Key: PrivateName | JSStringValue | SymbolValue;
|
||||
Decorators: DecoratorDefinitionRecord[] | undefined;
|
||||
readonly Initializers: FunctionObject[];
|
||||
readonly ExtraInitializers: FunctionObject[];
|
||||
}
|
||||
export interface ClassElementDefinitionRecord_Accessor {
|
||||
readonly Kind: 'accessor';
|
||||
readonly Key: PrivateName | JSStringValue | SymbolValue;
|
||||
// https://github.com/tc39/proposal-decorators/issues/572
|
||||
Get: FunctionObject;
|
||||
// https://github.com/tc39/proposal-decorators/issues/572
|
||||
Set: FunctionObject;
|
||||
readonly BackingStorageKey: PrivateName;
|
||||
Decorators: readonly DecoratorDefinitionRecord[] | undefined;
|
||||
readonly Initializers: FunctionObject[];
|
||||
readonly ExtraInitializers: FunctionObject[];
|
||||
}
|
||||
export interface ClassElementDefinitionRecord_Getter {
|
||||
readonly Kind: 'getter';
|
||||
readonly Key: PrivateName | JSStringValue | SymbolValue;
|
||||
// https://github.com/tc39/proposal-decorators/issues/572
|
||||
Get: FunctionObject;
|
||||
Decorators: readonly DecoratorDefinitionRecord[] | undefined;
|
||||
}
|
||||
export interface ClassElementDefinitionRecord_Setter {
|
||||
readonly Kind: 'setter';
|
||||
readonly Key: PrivateName | JSStringValue | SymbolValue;
|
||||
// https://github.com/tc39/proposal-decorators/issues/572
|
||||
Set: FunctionObject;
|
||||
Decorators: readonly DecoratorDefinitionRecord[] | undefined;
|
||||
}
|
||||
|
||||
// This is a struct defined as a marco.
|
||||
export const ClassElementDefinitionRecord = (function ClassElementDefinitionRecord(record: ClassElementDefinitionRecord) {
|
||||
Object.setPrototypeOf(record, ClassElementDefinitionRecord.prototype);
|
||||
return record;
|
||||
}) as {
|
||||
(record: ClassElementDefinitionRecord): ClassElementDefinitionRecord;
|
||||
[Symbol.hasInstance](instance: unknown): instance is ClassElementDefinitionRecord;
|
||||
};
|
||||
@@ -0,0 +1,24 @@
|
||||
import { Value } from '../value.mts';
|
||||
import { Q } from '../completion.mts';
|
||||
import { StringValue } from '../static-semantics/all.mts';
|
||||
import type { ParseNode } from '../parser/ParseNode.mts';
|
||||
import type { ValueEvaluator } from '../evaluator.mts';
|
||||
import { ClassDefinitionEvaluation, DecoratorListEvaluation } from './all.mts';
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-class-definitions-runtime-semantics-evaluation */
|
||||
// ClassExpression :
|
||||
// `class` ClassTail
|
||||
// `class` BindingIdentifier ClassTail
|
||||
export function* Evaluate_ClassExpression(ClassExpression: ParseNode.ClassExpression): ValueEvaluator {
|
||||
const { BindingIdentifier, ClassTail, Decorators } = ClassExpression;
|
||||
const sourceText = ClassExpression.sourceText;
|
||||
const decorators = Decorators ? Q(yield* DecoratorListEvaluation(Decorators)) : [];
|
||||
if (!BindingIdentifier) {
|
||||
// 1. Let value be ? ClassDefinitionEvaluation of ClassTail with arguments undefined and ''
|
||||
return Q(yield* ClassDefinitionEvaluation(ClassTail, Value.undefined, Value(''), sourceText, decorators));
|
||||
}
|
||||
// 1. Let className be StringValue of BindingIdentifier.
|
||||
const className = StringValue(BindingIdentifier);
|
||||
// 2. Let value be ? ClassDefinitionEvaluation of ClassTail with arguments className and className.
|
||||
return Q(yield* ClassDefinitionEvaluation(ClassTail, className, className, sourceText, decorators));
|
||||
}
|
||||
@@ -0,0 +1,189 @@
|
||||
import { surroundingAgent } from '../host-defined/engine.mts';
|
||||
import { X, Q } from '../completion.mts';
|
||||
import type { ParseNode } from '../parser/ParseNode.mts';
|
||||
import type { PlainEvaluator, ValueEvaluator } from '../evaluator.mts';
|
||||
import { Evaluate_PropertyName } from './PropertyName.mts';
|
||||
import {
|
||||
CreateBuiltinFunction, DefinePropertyOrThrow, MakeMethod, OrdinaryFunctionCreate, PrivateGet, PrivateSet, SymbolDescriptiveString,
|
||||
} from '#self';
|
||||
import {
|
||||
ClassElementDefinitionRecord,
|
||||
Descriptor,
|
||||
JSStringValue,
|
||||
SymbolValue,
|
||||
Value,
|
||||
type Arguments,
|
||||
type ECMAScriptFunctionObject, type FunctionCallContext, type FunctionObject, type ObjectValue, PrivateName, type PropertyKeyValue,
|
||||
} from '#self';
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-classfielddefinition-record-specification-type */
|
||||
export interface ClassFieldDefinitionRecord {
|
||||
readonly Name: PropertyKeyValue | PrivateName;
|
||||
readonly Initializer: ECMAScriptFunctionObject | undefined;
|
||||
}
|
||||
export const ClassFieldDefinitionRecord = function ClassFieldDefinitionRecord(value: ClassFieldDefinitionRecord) {
|
||||
Object.setPrototypeOf(value, ClassFieldDefinitionRecord.prototype);
|
||||
return value;
|
||||
} as {
|
||||
(value: ClassFieldDefinitionRecord): ClassFieldDefinitionRecord;
|
||||
[Symbol.hasInstance](instance: unknown): instance is ClassFieldDefinitionRecord;
|
||||
};
|
||||
|
||||
export function* ClassFieldDefinitionEvaluation(FieldDefinition: ParseNode.FieldDefinition, homeObject: ObjectValue): PlainEvaluator<ClassFieldDefinitionRecord> {
|
||||
const { ClassElementName, Initializer } = FieldDefinition;
|
||||
// 1. Let name be the result of evaluating ClassElementName.
|
||||
const name = Q(yield* Evaluate_PropertyName(ClassElementName));
|
||||
// 3. If Initializer is present, then
|
||||
let initializer;
|
||||
if (Initializer) {
|
||||
// a. Let formalParameterList be an instance of the production FormalParameters : [empty].
|
||||
const formalParameterList: readonly [] = [];
|
||||
// b. Let scope be the LexicalEnvironment of the running execution context.
|
||||
const scope = surroundingAgent.runningExecutionContext.LexicalEnvironment;
|
||||
// c. Let privateScope be the running execution context's PrivateEnvironment.
|
||||
const privateScope = surroundingAgent.runningExecutionContext.PrivateEnvironment;
|
||||
// d. Let sourceText be the empty sequence of Unicode code points.
|
||||
const sourceText = '';
|
||||
// e. Let initializer be ! OrdinaryFunctionCreate(%Function.prototype%, sourceText, formalParameterList, Initializer, non-lexical-this, scope, privateScope).
|
||||
initializer = X(OrdinaryFunctionCreate(
|
||||
surroundingAgent.intrinsic('%Function.prototype%'),
|
||||
sourceText,
|
||||
formalParameterList,
|
||||
Initializer,
|
||||
'non-lexical-this',
|
||||
scope,
|
||||
privateScope,
|
||||
));
|
||||
// f. Perform MakeMethod(initializer, homeObject).
|
||||
MakeMethod(initializer, homeObject);
|
||||
// g. Set initializer.[[ClassFieldInitializerName]] to name.
|
||||
initializer.ClassFieldInitializerName = name;
|
||||
} else { // 4. Else,
|
||||
// a. Let initializer be empty.
|
||||
initializer = undefined;
|
||||
}
|
||||
// 5. Return the ClassFieldDefinition Record { [[Name]]: name, [[Initializer]]: initializer }.
|
||||
return ClassFieldDefinitionRecord({
|
||||
Name: name,
|
||||
Initializer: initializer,
|
||||
});
|
||||
}
|
||||
|
||||
/** https://arai-a.github.io/ecma262-compare/snapshot.html?pr=2417#sec-runtime-semantics-classfielddefinitionevaluation */
|
||||
export function* ClassFieldDefinitionEvaluation_decorator(FieldDefinition: ParseNode.FieldDefinition, homeObject: ObjectValue): PlainEvaluator<ClassElementDefinitionRecord> {
|
||||
const { ClassElementName, Initializer, accessor } = FieldDefinition;
|
||||
|
||||
if (!accessor) {
|
||||
const name = Q(yield* Evaluate_PropertyName(ClassElementName));
|
||||
const initializers: FunctionObject[] = [];
|
||||
const extraInitializers: FunctionObject[] = [];
|
||||
if (Initializer) {
|
||||
const initializer = CreateFieldInitializerFunction(homeObject, name, Initializer);
|
||||
// TODO(decorator): spec bug. ApplyDecoratorsToElementDefinition unshift decorator initializers into this array, but read it in order, so the spec order is wrong (be like [decorator2, decorator1, syntaxInit], but the correct order should be [syntaxInit, decorator2, decorator1])
|
||||
if (surroundingAgent.feature('decorators.no-bugfix.1')) {
|
||||
initializers.push(initializer);
|
||||
} else {
|
||||
initializers[-1] = initializer;
|
||||
}
|
||||
}
|
||||
return ClassElementDefinitionRecord({
|
||||
Kind: 'field',
|
||||
Key: name,
|
||||
Initializers: initializers,
|
||||
ExtraInitializers: extraInitializers,
|
||||
Decorators: undefined,
|
||||
});
|
||||
} else {
|
||||
const name = Q(yield* Evaluate_PropertyName(ClassElementName));
|
||||
let readableName: JSStringValue;
|
||||
if (name instanceof PrivateName) {
|
||||
readableName = name.Description;
|
||||
} else if (name instanceof SymbolValue) {
|
||||
readableName = SymbolDescriptiveString(name);
|
||||
} else {
|
||||
readableName = name;
|
||||
}
|
||||
const privateStateDesc = `${readableName.stringValue()} accessor storage`;
|
||||
const privateStateName = new PrivateName(Value(privateStateDesc));
|
||||
const getter = MakeAutoAccessorGetter(homeObject, name, privateStateName);
|
||||
const setter = MakeAutoAccessorSetter(homeObject, name, privateStateName);
|
||||
const initializers = [];
|
||||
const extraInitializers: FunctionObject[] = [];
|
||||
if (Initializer) {
|
||||
const initializer = CreateFieldInitializerFunction(homeObject, name, Initializer);
|
||||
// TODO(decorator): spec bug. ApplyDecoratorsToElementDefinition unshift decorator initializers into this array, but read it in order, so the spec order is wrong (be like [decorator2, decorator1, syntaxInit], but the correct order should be [syntaxInit, decorator2, decorator1])
|
||||
if (surroundingAgent.feature('decorators.no-bugfix.1')) {
|
||||
initializers.push(initializer);
|
||||
} else {
|
||||
initializers[-1] = initializer;
|
||||
}
|
||||
}
|
||||
if (!(name instanceof PrivateName)) {
|
||||
const desc = new Descriptor({
|
||||
Get: getter,
|
||||
Set: setter,
|
||||
Enumerable: Value.true,
|
||||
Configurable: Value.true,
|
||||
});
|
||||
Q(yield* DefinePropertyOrThrow(homeObject, name, desc));
|
||||
}
|
||||
return ClassElementDefinitionRecord({
|
||||
Kind: 'accessor',
|
||||
Key: name,
|
||||
Get: getter,
|
||||
Set: setter,
|
||||
BackingStorageKey: privateStateName,
|
||||
Initializers: initializers,
|
||||
ExtraInitializers: extraInitializers,
|
||||
Decorators: undefined,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/** https://arai-a.github.io/ecma262-compare/snapshot.html?pr=2417#sec-createfieldinitializerfunction */
|
||||
export function CreateFieldInitializerFunction(homeObject: ObjectValue, propName: PropertyKeyValue | PrivateName, Initializer: ParseNode.AssignmentExpressionOrHigher) {
|
||||
const formalParameterList: readonly [] = [];
|
||||
const scope = surroundingAgent.runningExecutionContext.LexicalEnvironment;
|
||||
const privateScope = surroundingAgent.runningExecutionContext.PrivateEnvironment;
|
||||
const sourceText = '';
|
||||
const initializer = OrdinaryFunctionCreate(
|
||||
surroundingAgent.intrinsic('%Function.prototype%'),
|
||||
sourceText,
|
||||
formalParameterList,
|
||||
Initializer,
|
||||
'non-lexical-this',
|
||||
scope,
|
||||
privateScope,
|
||||
);
|
||||
MakeMethod(initializer, homeObject);
|
||||
initializer.ClassFieldInitializerName = propName;
|
||||
return initializer;
|
||||
}
|
||||
|
||||
/** https://arai-a.github.io/ecma262-compare/snapshot.html?pr=2417#sec-makeautoaccessorgetter */
|
||||
export function MakeAutoAccessorGetter(_homeObject: ObjectValue, _name: PropertyKeyValue | PrivateName, privateStateName: PrivateName) {
|
||||
const getterClosure = function* getterClosure(_args: Arguments, { thisValue }: FunctionCallContext): ValueEvaluator {
|
||||
const o = thisValue as ObjectValue;
|
||||
return Q(yield* PrivateGet(o, privateStateName));
|
||||
};
|
||||
const getter = CreateBuiltinFunction(getterClosure, 0, Value('get'), []);
|
||||
// TODO(decorator): spec bug, SetFunctionName only accepts ECMAScriptFunctionObject, but the name is already set when calling CreateBuiltinFunction
|
||||
// SetFunctionName(getter, name, Value('get'));
|
||||
// TODO(decorator): https://github.com/tc39/proposal-decorators/issues/568
|
||||
// MakeMethod(getter, homeObject);
|
||||
return getter;
|
||||
}
|
||||
|
||||
export function MakeAutoAccessorSetter(_homeObject: ObjectValue, _name: PropertyKeyValue | PrivateName, privateStateName: PrivateName) {
|
||||
const setterClosure = function* setterClosure([value = Value.undefined]: Arguments, { thisValue }: FunctionCallContext): ValueEvaluator {
|
||||
const o = thisValue as ObjectValue;
|
||||
Q(yield* PrivateSet(o, privateStateName, value));
|
||||
return Value.undefined;
|
||||
};
|
||||
const setter = CreateBuiltinFunction(setterClosure, 1, Value('set'), []);
|
||||
// TODO(decorator): spec bug
|
||||
// SetFunctionName(setter, name, Value('set'));
|
||||
// TODO(decorator): https://github.com/tc39/proposal-decorators/issues/568
|
||||
// MakeMethod(setter, homeObject);
|
||||
return setter;
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
import { surroundingAgent } from '../host-defined/engine.mts';
|
||||
import { X } from '../completion.mts';
|
||||
import type { ParseNode } from '../parser/ParseNode.mts';
|
||||
import {
|
||||
MakeMethod,
|
||||
OrdinaryFunctionCreate,
|
||||
type ECMAScriptFunctionObject,
|
||||
ObjectValue,
|
||||
} from '#self';
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-classstaticblockdefinition-record-specification-type */
|
||||
export interface ClassStaticBlockDefinitionRecord {
|
||||
readonly BodyFunction: ECMAScriptFunctionObject;
|
||||
}
|
||||
export const ClassStaticBlockDefinitionRecord = function ClassStaticBlockDefinitionRecord(value: ClassStaticBlockDefinitionRecord) {
|
||||
Object.setPrototypeOf(value, ClassStaticBlockDefinitionRecord.prototype);
|
||||
return value;
|
||||
} as {
|
||||
(value: ClassStaticBlockDefinitionRecord): ClassStaticBlockDefinitionRecord;
|
||||
[Symbol.hasInstance](instance: unknown): instance is ClassStaticBlockDefinitionRecord;
|
||||
};
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-runtime-semantics-classstaticblockdefinitionevaluation */
|
||||
// ClassStaticBlock : `static` `{` ClassStaticBlockBody `}`
|
||||
export function ClassStaticBlockDefinitionEvaluation({ ClassStaticBlockBody }: ParseNode.ClassStaticBlock, homeObject: ObjectValue) {
|
||||
// 1. Let lex be the running execution context's LexicalEnvironment.
|
||||
const lex = surroundingAgent.runningExecutionContext.LexicalEnvironment;
|
||||
// 2. Let privateEnv be the running execution context's PrivateEnvironment.
|
||||
const privateEnv = surroundingAgent.runningExecutionContext.PrivateEnvironment;
|
||||
// 3. Let sourceText be the empty sequence of Unicode code points.
|
||||
const sourceText = '';
|
||||
// 4. Let formalParameters be an instance of the production FormalParameters : [empty] .
|
||||
const formalParameters: readonly [] = [];
|
||||
// 5. Let bodyFunction be OrdinaryFunctionCreate(%Function.prototype%, sourceText, formalParameters, ClassStaticBlockBody, non-lexical-this, lex, privateEnv).
|
||||
const bodyFunction = X(OrdinaryFunctionCreate(
|
||||
surroundingAgent.intrinsic('%Function.prototype%'),
|
||||
sourceText,
|
||||
formalParameters,
|
||||
ClassStaticBlockBody,
|
||||
'non-lexical-this',
|
||||
lex,
|
||||
privateEnv,
|
||||
));
|
||||
// 6. Perform MakeMethod(bodyFunction, homeObject).
|
||||
X(MakeMethod(bodyFunction, homeObject));
|
||||
// 7. Return the ClassStaticBlockDefinition Record { [[BodyFunction]]: bodyFunction }.
|
||||
return ClassStaticBlockDefinitionRecord({ BodyFunction: bodyFunction });
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
import { Q } from '../completion.mts';
|
||||
import { Evaluate, type ValueEvaluator } from '../evaluator.mts';
|
||||
import { Value } from '../value.mts';
|
||||
import type { ParseNode } from '../parser/ParseNode.mts';
|
||||
import { GetValue } from '#self';
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-binary-logical-operators-runtime-semantics-evaluation */
|
||||
// CoalesceExpression :
|
||||
// CoalesceExpressionHead `??` BitwiseORExpression
|
||||
export function* Evaluate_CoalesceExpression({ CoalesceExpressionHead, BitwiseORExpression }: ParseNode.CoalesceExpression): ValueEvaluator {
|
||||
// 1. Let lref be the result of evaluating |CoalesceExpressionHead|.
|
||||
const lref = Q(yield* Evaluate(CoalesceExpressionHead));
|
||||
// 2. Let lval be ? GetValue(lref).
|
||||
const lval = Q(yield* GetValue(lref));
|
||||
// 3. If lval is *undefined* or *null*,
|
||||
if (lval === Value.undefined || lval === Value.null) {
|
||||
// a. Let rref be the result of evaluating |BitwiseORExpression|.
|
||||
const rref = Q(yield* Evaluate(BitwiseORExpression));
|
||||
// b. Return ? GetValue(rref).
|
||||
return Q(yield* GetValue(rref));
|
||||
}
|
||||
// 4. Otherwise, return lval.
|
||||
return lval;
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
import { Evaluate } from '../evaluator.mts';
|
||||
import { Q } from '../completion.mts';
|
||||
import type { ParseNode } from '../parser/ParseNode.mts';
|
||||
import { GetValue } from '#self';
|
||||
import type { Value, ValueEvaluator } from '#self';
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-comma-operator-runtime-semantics-evaluation */
|
||||
// Expression :
|
||||
// AssignmentExpression
|
||||
// Expression `,` AssignmentExpression
|
||||
export function* Evaluate_CommaOperator({ ExpressionList }: ParseNode.CommaOperator): ValueEvaluator {
|
||||
let result!: Value;
|
||||
for (const Expression of ExpressionList) {
|
||||
const lref = Q(yield* Evaluate(Expression));
|
||||
result = Q(yield* GetValue(lref));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
import { Value } from '../value.mts';
|
||||
import { Evaluate, type ValueEvaluator } from '../evaluator.mts';
|
||||
import { Q, X } from '../completion.mts';
|
||||
import type { ParseNode } from '../parser/ParseNode.mts';
|
||||
import { ToBoolean, GetValue } from '#self';
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-conditional-operator-runtime-semantics-evaluation */
|
||||
// ConditionalExpression :
|
||||
// ShortCircuitExpression `?` AssignmentExpression `:` AssignmentExpression
|
||||
export function* Evaluate_ConditionalExpression({
|
||||
ShortCircuitExpression,
|
||||
AssignmentExpression_a,
|
||||
AssignmentExpression_b,
|
||||
}: ParseNode.ConditionalExpression): ValueEvaluator {
|
||||
// 1. Let lref be the result of evaluating ShortCircuitExpression.
|
||||
const lref = Q(yield* Evaluate(ShortCircuitExpression));
|
||||
// 2. Let lval be ! ToBoolean(? GetValue(lref)).
|
||||
const lval = X(ToBoolean(Q(yield* GetValue(lref))));
|
||||
// 3. If lval is true, then
|
||||
if (lval === Value.true) {
|
||||
// a. Let trueRef be the result of evaluating the first AssignmentExpression.
|
||||
const trueRef = Q(yield* Evaluate(AssignmentExpression_a));
|
||||
// b. Return ? GetValue(trueRef).
|
||||
return Q(yield* GetValue(trueRef));
|
||||
} else { // 4. Else,
|
||||
// a. Let falseRef be the result of evaluating the second AssignmentExpression.
|
||||
const falseRef = Q(yield* Evaluate(AssignmentExpression_b));
|
||||
// b. Return ? GetValue(falseRef).
|
||||
return Q(yield* GetValue(falseRef));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
import { Completion } from '../completion.mts';
|
||||
import type { ParseNode } from '../parser/ParseNode.mts';
|
||||
import { StringValue } from '../static-semantics/all.mts';
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-continue-statement-runtime-semantics-evaluation */
|
||||
// ContinueStatement :
|
||||
// `continue` `;`
|
||||
// `continue` LabelIdentifier `;`
|
||||
export function Evaluate_ContinueStatement({ LabelIdentifier }: ParseNode.ContinueStatement) {
|
||||
if (!LabelIdentifier) {
|
||||
// 1. Return Completion { [[Type]]: continue, [[Value]]: empty, [[Target]]: empty }.
|
||||
return new Completion({ Type: 'continue', Value: undefined, Target: undefined });
|
||||
}
|
||||
// 1. Let label be the StringValue of LabelIdentifier.
|
||||
const label = StringValue(LabelIdentifier);
|
||||
// 2. Return Completion { [[Type]]: continue, [[Value]]: empty, [[Target]]: label }.
|
||||
return new Completion({ Type: 'continue', Value: undefined, Target: label });
|
||||
}
|
||||
@@ -0,0 +1,178 @@
|
||||
import { Q, ThrowCompletion, X } from '../completion.mts';
|
||||
import {
|
||||
HostEnsureCanCompileStrings,
|
||||
surroundingAgent,
|
||||
} from '../host-defined/engine.mts';
|
||||
import { Parser, wrappedParse } from '../parse.mts';
|
||||
import { Token } from '../parser/tokens.mts';
|
||||
import {
|
||||
Descriptor, UndefinedValue, Value,
|
||||
type Arguments,
|
||||
} from '../value.mts';
|
||||
import { __ts_cast__, OutOfRange } from '../helpers.mts';
|
||||
import type { ParseNode } from '../parser/ParseNode.mts';
|
||||
import {
|
||||
Assert,
|
||||
DefinePropertyOrThrow,
|
||||
GetPrototypeFromConstructor,
|
||||
MakeConstructor,
|
||||
OrdinaryFunctionCreate,
|
||||
OrdinaryObjectCreate,
|
||||
SetFunctionName,
|
||||
ToString,
|
||||
type FunctionObject,
|
||||
type Intrinsics,
|
||||
} from '#self';
|
||||
|
||||
export function* CreateDynamicFunction(constructor: FunctionObject, newTarget: FunctionObject | UndefinedValue, kind: 'normal' | 'generator' | 'async' | 'asyncGenerator', parameterArgs: Arguments, bodyArg: Value) {
|
||||
// 6. If newTarget is undefined, set newTarget to constructor.
|
||||
if (newTarget instanceof UndefinedValue) {
|
||||
newTarget = constructor;
|
||||
}
|
||||
// 7. If kind is normal, then
|
||||
let fallbackProto: keyof Intrinsics;
|
||||
let prefix;
|
||||
if (kind === 'normal') {
|
||||
prefix = 'function';
|
||||
// a. Let goal be the grammar symbol FunctionBody[~Yield, ~Await].
|
||||
// b. Let parameterGoal be the grammar symbol FormalParameters[~Yield, ~Await].
|
||||
// c. Let fallbackProto be "%Function.prototype%".
|
||||
fallbackProto = '%Function.prototype%';
|
||||
} else if (kind === 'generator') { // 8. Else if kind is generator, then
|
||||
prefix = 'function*';
|
||||
// a. Let goal be the grammar symbol GeneratorBody.
|
||||
// b. Let parameterGoal be the grammar symbol FormalParameters[+Yield, ~Await].
|
||||
// c. Let fallbackProto be "%GeneratorFunction.prototype%".
|
||||
fallbackProto = '%GeneratorFunction.prototype%';
|
||||
} else if (kind === 'async') { // 9. Else if kind is async, then
|
||||
prefix = 'async function';
|
||||
// a. Let goal be the grammar symbol AsyncBody.
|
||||
// b. Let parameterGoal be the grammar symbol FormalParameters[~Yield, +Await].
|
||||
// c. Let fallbackProto be "%AsyncFunction.prototype%".
|
||||
fallbackProto = '%AsyncFunction.prototype%';
|
||||
} else { // 10. Else,
|
||||
// a. Assert: kind is asyncGenerator.
|
||||
Assert(kind === 'asyncGenerator');
|
||||
prefix = 'async function*';
|
||||
// b. Let goal be the grammar symbol AsyncGeneratorBody.
|
||||
// c. Let parameterGoal be the grammar symbol FormalParameters[+Yield, +Await].
|
||||
// d. Let fallbackProto be "%AsyncGeneratorFunction.prototype%".
|
||||
fallbackProto = '%AsyncGeneratorFunction.prototype%';
|
||||
}
|
||||
// 11. Let argCount be the number of elements in args.
|
||||
const argCount = parameterArgs.length;
|
||||
const parameterStrings: string[] = [];
|
||||
for (const arg of parameterArgs) {
|
||||
parameterStrings.push(Q(yield* ToString(arg!)).stringValue());
|
||||
}
|
||||
const bodyString = Q(yield* ToString(bodyArg)).stringValue();
|
||||
const currentRealm = surroundingAgent.currentRealmRecord;
|
||||
Q(yield* HostEnsureCanCompileStrings(currentRealm, parameterStrings, bodyString, false));
|
||||
// 12. Let P be the empty String.
|
||||
let P = '';
|
||||
if (argCount > 0) {
|
||||
P = parameterStrings[0];
|
||||
// d. Let k be 1.
|
||||
let k = 1;
|
||||
// e. Repeat, while k < argCount - 1
|
||||
while (k < argCount) {
|
||||
const nextArgString = parameterStrings[k];
|
||||
// iii. Set P to the string-concatenation of the previous value of P, "," (a comma), and nextArgString.
|
||||
P = `${P},${nextArgString}`;
|
||||
// iv. Set k to k + 1.
|
||||
k += 1;
|
||||
}
|
||||
}
|
||||
const bodyParseString = `\u{000A}${bodyString}\u{000A}`;
|
||||
// 18. Let sourceString be the string-concatenation of prefix, " anonymous(", P, 0x000A (LINE FEED), ") {", bodyString, and "}".
|
||||
const sourceString = `${prefix} anonymous(${P}\u{000A}) {${bodyParseString}}`;
|
||||
// 19. Let sourceText be ! UTF16DecodeString(sourceString).
|
||||
const sourceText = sourceString;
|
||||
// 20. Perform the following substeps in an implementation-dependent order, possibly interleaving parsing and error detection:
|
||||
// a. Let parameters be the result of parsing ! UTF16DecodeString(P), using parameterGoal as the goal symbol. Throw a SyntaxError exception if the parse fails.
|
||||
// b. Let body be the result of parsing ! UTF16DecodeString(bodyString), using goal as the goal symbol. Throw a SyntaxError exception if the parse fails.
|
||||
// c. Let strict be ContainsUseStrict of body.
|
||||
// d. If any static semantics errors are detected for parameters or body, throw a SyntaxError exception. If strict is true, the Early Error rules for UniqueFormalParameters:FormalParameters are applied.
|
||||
// e. If strict is true and IsSimpleParameterList of parameters is false, throw a SyntaxError exception.
|
||||
// f. If any element of the BoundNames of parameters also occurs in the LexicallyDeclaredNames of body, throw a SyntaxError exception.
|
||||
// g. If body Contains SuperCall is true, throw a SyntaxError exception.
|
||||
// h. If parameters Contains SuperCall is true, throw a SyntaxError exception.
|
||||
// i. If body Contains SuperProperty is true, throw a SyntaxError exception.
|
||||
// j. If parameters Contains SuperProperty is true, throw a SyntaxError exception.
|
||||
// k. If kind is generator or asyncGenerator, then
|
||||
// i. If parameters Contains YieldExpression is true, throw a SyntaxError exception.
|
||||
// l. If kind is async or asyncGenerator, then
|
||||
// i. If parameters Contains AwaitExpression is true, throw a SyntaxError exception.
|
||||
// m. If strict is true, then
|
||||
// i. If BoundNames of parameters contains any duplicate elements, throw a SyntaxError exception.
|
||||
let parameters;
|
||||
let body;
|
||||
let scriptId;
|
||||
{
|
||||
const f = wrappedParse({ source: sourceString }, (p) => {
|
||||
const r = p.parseExpression();
|
||||
p.expect(Token.EOS);
|
||||
return r;
|
||||
});
|
||||
scriptId = surroundingAgent.addDynamicParsedSource(surroundingAgent.currentRealmRecord, sourceString, f);
|
||||
if (Array.isArray(f)) {
|
||||
Parser.decorateSyntaxErrorWithScriptId(f[0], scriptId);
|
||||
return ThrowCompletion(f[0]);
|
||||
}
|
||||
__ts_cast__<ParseNode.FunctionExpression | ParseNode.GeneratorExpression | ParseNode.AsyncFunctionExpression | ParseNode.AsyncGeneratorExpression>(f);
|
||||
parameters = f.FormalParameters;
|
||||
switch (kind) {
|
||||
case 'normal':
|
||||
body = (f as ParseNode.FunctionExpression).FunctionBody;
|
||||
break;
|
||||
case 'generator':
|
||||
body = (f as ParseNode.GeneratorExpression).GeneratorBody;
|
||||
break;
|
||||
case 'async':
|
||||
body = (f as ParseNode.AsyncFunctionExpression).AsyncBody;
|
||||
break;
|
||||
case 'asyncGenerator':
|
||||
body = (f as ParseNode.AsyncGeneratorExpression).AsyncGeneratorBody;
|
||||
break;
|
||||
default:
|
||||
throw new OutOfRange('kind', kind);
|
||||
}
|
||||
}
|
||||
// 21. Let proto be ? GetPrototypeFromConstructor(newTarget, fallbackProto).
|
||||
const proto = Q(yield* GetPrototypeFromConstructor(newTarget, fallbackProto));
|
||||
// 23. Let scope be realmF.[[GlobalEnv]].
|
||||
const env = currentRealm.GlobalEnv;
|
||||
const privateEnv = Value.null;
|
||||
// 24. Let F be ! OrdinaryFunctionCreate(proto, sourceText, parameters, body, non-lexical-this, scope, privateEnv).
|
||||
const F = X(OrdinaryFunctionCreate(proto, sourceText, parameters, body, 'non-lexical-this', env, privateEnv));
|
||||
F.scriptId = scriptId;
|
||||
// 25. Perform SetFunctionName(F, "anonymous").
|
||||
SetFunctionName(F, Value('anonymous'));
|
||||
// 26. If kind is generator, then
|
||||
if (kind === 'generator') {
|
||||
// a. Let prototype be OrdinaryObjectCreate(%GeneratorFunction.prototype.prototype%).
|
||||
const prototype = OrdinaryObjectCreate(surroundingAgent.intrinsic('%GeneratorFunction.prototype.prototype%'));
|
||||
// b. Perform DefinePropertyOrThrow(F, "prototype", PropertyDescriptor { [[Value]]: prototype, [[Writable]]: true, [[Enumerable]]: false, [[Configurable]]: false }).
|
||||
X(DefinePropertyOrThrow(F, Value('prototype'), Descriptor({
|
||||
Value: prototype,
|
||||
Writable: Value.true,
|
||||
Enumerable: Value.false,
|
||||
Configurable: Value.false,
|
||||
})));
|
||||
} else if (kind === 'asyncGenerator') { // 27. Else if kind is asyncGenerator, then
|
||||
// a. Let prototype be OrdinaryObjectCreate(%AsyncGeneratorFunction.prototype.prototype%).
|
||||
const prototype = OrdinaryObjectCreate(surroundingAgent.intrinsic('%AsyncGeneratorFunction.prototype.prototype%'));
|
||||
// b. Perform DefinePropertyOrThrow(F, "prototype", PropertyDescriptor { [[Value]]: prototype, [[Writable]]: true, [[Enumerable]]: false, [[Configurable]]: false }).
|
||||
X(DefinePropertyOrThrow(F, Value('prototype'), Descriptor({
|
||||
Value: prototype,
|
||||
Writable: Value.true,
|
||||
Enumerable: Value.false,
|
||||
Configurable: Value.false,
|
||||
})));
|
||||
} else if (kind === 'normal') { // 28. Else if kind is normal, then perform MakeConstructor(F).
|
||||
MakeConstructor(F);
|
||||
}
|
||||
// 29. NOTE: Functions whose kind is async are not constructible and do not have a [[Construct]] internal method or a "prototype" property.
|
||||
// 20. Return F.
|
||||
return F;
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
import { surroundingAgent } from '../host-defined/engine.mts';
|
||||
import { NormalCompletion } from '../completion.mts';
|
||||
import type { ParseNode } from '../parser/ParseNode.mts';
|
||||
import { Assert, type StatementEvaluator } from '#self';
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-debugger-statement-runtime-semantics-evaluation */
|
||||
// DebuggerStatement : `debugger` `;`
|
||||
export function* Evaluate_DebuggerStatement(_node: ParseNode.DebuggerStatement): StatementEvaluator {
|
||||
// 1. If an implementation-defined debugging facility is available and enabled, then
|
||||
if (surroundingAgent.hostDefinedOptions.onDebugger) {
|
||||
// a. Perform an implementation-defined debugging action.
|
||||
// b. Let result be an implementation-defined Completion value.
|
||||
const completion = yield { type: 'debugger' };
|
||||
Assert(completion.type === 'debugger-resume');
|
||||
return completion.value;
|
||||
}
|
||||
// 2. Return result.
|
||||
return NormalCompletion(undefined);
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
import { surroundingAgent } from '../host-defined/engine.mts';
|
||||
import { Q } from '../completion.mts';
|
||||
import type { ParseNode } from '../parser/ParseNode.mts';
|
||||
import type { PlainEvaluator } from '../evaluator.mts';
|
||||
import { Evaluate_PropertyName } from './all.mts';
|
||||
import { OrdinaryFunctionCreate, MakeMethod, sourceTextMatchedBy } from '#self';
|
||||
import type {
|
||||
ECMAScriptFunctionObject, ObjectValue, PrivateName, PropertyKeyValue,
|
||||
} from '#self';
|
||||
|
||||
export interface DefineMethodRecord {
|
||||
readonly Key: PropertyKeyValue | PrivateName;
|
||||
readonly Closure: ECMAScriptFunctionObject;
|
||||
}
|
||||
/** https://tc39.es/ecma262/#sec-runtime-semantics-definemethod */
|
||||
export function* DefineMethod(MethodDefinition: ParseNode.MethodDefinition, object: ObjectValue, functionPrototype?: ObjectValue): PlainEvaluator<DefineMethodRecord> {
|
||||
const { ClassElementName, UniqueFormalParameters, FunctionBody } = MethodDefinition;
|
||||
// 1. Let propKey be the result of evaluating ClassElementName.
|
||||
const propKey = Q(yield* Evaluate_PropertyName(ClassElementName));
|
||||
// 3. Let scope be the running execution context's LexicalEnvironment.
|
||||
const scope = surroundingAgent.runningExecutionContext.LexicalEnvironment;
|
||||
// 4. Let privateScope be the running execution context's PrivateEnvironment.
|
||||
const privateScope = surroundingAgent.runningExecutionContext.PrivateEnvironment;
|
||||
let prototype;
|
||||
// 5. If functionPrototype is present as a parameter, then
|
||||
if (functionPrototype !== undefined) {
|
||||
// a. Let prototype be functionPrototype.
|
||||
prototype = functionPrototype;
|
||||
} else { // 6. Else,
|
||||
// a. Let prototype be %Function.prototype%.
|
||||
prototype = surroundingAgent.intrinsic('%Function.prototype%');
|
||||
}
|
||||
// 7. Let sourceText be the source text matched by MethodDefinition.
|
||||
const sourceText = sourceTextMatchedBy(MethodDefinition);
|
||||
// 8. Let closure be OrdinaryFunctionCreate(prototype, sourceText, UniqueFormalParameters, FunctionBody, non-lexical-this, scope, privateScope).
|
||||
const closure = OrdinaryFunctionCreate(prototype, sourceText, UniqueFormalParameters!, FunctionBody, 'non-lexical-this', scope, privateScope);
|
||||
// 9. Perform MakeMethod(closure, object).
|
||||
MakeMethod(closure, object);
|
||||
// 10. Return the Record { [[Key]]: propKey, [[Closure]]: closure }.
|
||||
return { Key: propKey, Closure: closure };
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
import { NormalCompletion } from '../completion.mts';
|
||||
import type { ParseNode } from '../parser/ParseNode.mts';
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-empty-statement-runtime-semantics-evaluation */
|
||||
// EmptyStatement : `;`
|
||||
export function Evaluate_EmptyStatement(_EmptyStatement: ParseNode.EmptyStatement) {
|
||||
// 1. Return NormalCompletion(empty).
|
||||
return NormalCompletion(undefined);
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
import { Q, X } from '../completion.mts';
|
||||
import { Evaluate } from '../evaluator.mts';
|
||||
import { Value } from '../value.mts';
|
||||
import { OutOfRange } from '../helpers.mts';
|
||||
import type { ParseNode } from '../parser/ParseNode.mts';
|
||||
import {
|
||||
IsLooselyEqual,
|
||||
GetValue,
|
||||
IsStrictlyEqual,
|
||||
} from '#self';
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-equality-operators-runtime-semantics-evaluation */
|
||||
// EqualityExpression :
|
||||
// EqualityExpression `==` RelationalExpression
|
||||
// EqualityExpression `!=` RelationalExpression
|
||||
// EqualityExpression `===` RelationalExpression
|
||||
// EqualityExpression `!==` RelationalExpression
|
||||
export function* Evaluate_EqualityExpression({ EqualityExpression, operator, RelationalExpression }: ParseNode.EqualityExpression) {
|
||||
// 1. Let lref be the result of evaluating EqualityExpression.
|
||||
const lref = Q(yield* Evaluate(EqualityExpression));
|
||||
// 2. Let lval be ? GetValue(lref).
|
||||
const lval = Q(yield* GetValue(lref));
|
||||
// 3. Let rref be the result of evaluating RelationalExpression.
|
||||
const rref = Q(yield* Evaluate(RelationalExpression));
|
||||
// 4. Let rval be ? GetValue(rref).
|
||||
const rval = Q(yield* GetValue(rref));
|
||||
switch (operator) {
|
||||
case '==':
|
||||
// 5. Return the result of performing Abstract Equality Comparison rval == lval.
|
||||
return yield* IsLooselyEqual(rval, lval);
|
||||
case '!=': {
|
||||
// 5. Let r be the result of performing Abstract Equality Comparison rval == lval.
|
||||
const r = yield* IsLooselyEqual(rval, lval);
|
||||
Q(r);
|
||||
// 7. If r is true, return false. Otherwise, return true.
|
||||
if (r === Value.true) {
|
||||
return Value.false;
|
||||
} else {
|
||||
return Value.true;
|
||||
}
|
||||
}
|
||||
case '===':
|
||||
// 5. Return the result of performing Strict Equality Comparison rval === lval.
|
||||
return IsStrictlyEqual(rval, lval);
|
||||
case '!==': {
|
||||
// 5. Let r be the result of performing Strict Equality Comparison rval === lval.
|
||||
// 6. Assert: r is a normal completion.
|
||||
const r = X(IsStrictlyEqual(rval, lval));
|
||||
// 7. If r.[[Value]] is true, return false. Otherwise, return true.
|
||||
if (r === Value.true) {
|
||||
return Value.false;
|
||||
} else {
|
||||
return Value.true;
|
||||
}
|
||||
}
|
||||
|
||||
default:
|
||||
throw new OutOfRange('Evaluate_EqualityExpression', operator);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,206 @@
|
||||
import { surroundingAgent } from '../host-defined/engine.mts';
|
||||
import { Value, type Arguments } from '../value.mts';
|
||||
import {
|
||||
Completion,
|
||||
AbruptCompletion,
|
||||
Q, X,
|
||||
EnsureCompletion,
|
||||
ReturnCompletion,
|
||||
} from '../completion.mts';
|
||||
import { Evaluate, type StatementEvaluator } from '../evaluator.mts';
|
||||
import { IsAnonymousFunctionDefinition, type FunctionDeclaration } from '../static-semantics/all.mts';
|
||||
import type { ParseNode } from '../parser/ParseNode.mts';
|
||||
import type { Mutable } from '../helpers.mts';
|
||||
import {
|
||||
Evaluate_FunctionStatementList,
|
||||
FunctionDeclarationInstantiation,
|
||||
NamedEvaluation,
|
||||
} from './all.mts';
|
||||
import {
|
||||
Assert,
|
||||
AsyncFunctionStart,
|
||||
Call,
|
||||
GeneratorStart,
|
||||
NewPromiseCapability,
|
||||
OrdinaryCreateFromConstructor,
|
||||
AsyncGeneratorStart,
|
||||
GetValue,
|
||||
type ECMAScriptFunctionObject,
|
||||
type GeneratorObject,
|
||||
type AsyncGeneratorObject,
|
||||
type Body,
|
||||
} from '#self';
|
||||
|
||||
export function Evaluate_AnyFunctionBody({ FunctionStatementList }: ParseNode.FunctionBody | ParseNode.AsyncBody | ParseNode.GeneratorBody | ParseNode.AsyncGeneratorBody) {
|
||||
return Evaluate_FunctionStatementList(FunctionStatementList);
|
||||
}
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-function-definitions-runtime-semantics-evaluatebody */
|
||||
// FunctionBody : FunctionStatementList
|
||||
export function* EvaluateBody_FunctionBody({ FunctionStatementList }: ParseNode.FunctionBody, functionObject: ECMAScriptFunctionObject, argumentsList: Arguments) {
|
||||
// 1. Perform ? FunctionDeclarationInstantiation(functionObject, argumentsList).
|
||||
Q(yield* FunctionDeclarationInstantiation(functionObject, argumentsList));
|
||||
// 2. Return the result of evaluating FunctionStatementList.
|
||||
return yield* Evaluate_FunctionStatementList(FunctionStatementList);
|
||||
}
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-arrow-function-definitions-runtime-semantics-evaluation */
|
||||
// ExpressionBody : AssignmentExpression
|
||||
export function* Evaluate_ExpressionBody({ AssignmentExpression }: ParseNode.ExpressionBody): StatementEvaluator {
|
||||
// 1. Let exprRef be the result of evaluating AssignmentExpression.
|
||||
const exprRef = Q(yield* Evaluate(AssignmentExpression));
|
||||
// 2. Let exprValue be ? GetValue(exprRef).
|
||||
const exprValue = Q(yield* GetValue(exprRef));
|
||||
// 3. Return Completion { [[Type]]: return, [[Value]]: exprValue, [[Target]]: empty }.
|
||||
return new Completion({ Type: 'return', Value: exprValue, Target: undefined });
|
||||
}
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-arrow-function-definitions-runtime-semantics-evaluatebody */
|
||||
// ConciseBody : ExpressionBody
|
||||
export function* EvaluateBody_ConciseBody({ ExpressionBody }: ParseNode.ConciseBody, functionObject: ECMAScriptFunctionObject, argumentsList: Arguments) {
|
||||
// 1. Perform ? FunctionDeclarationInstantiation(functionObject, argumentsList).
|
||||
Q(yield* FunctionDeclarationInstantiation(functionObject, argumentsList));
|
||||
// 2. Return the result of evaluating ExpressionBody.
|
||||
return yield* Evaluate(ExpressionBody);
|
||||
}
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-async-arrow-function-definitions-EvaluateBody */
|
||||
// AsyncConciseBody : ExpressionBody
|
||||
function* EvaluateBody_AsyncConciseBody({ ExpressionBody }: ParseNode.AsyncConciseBody, functionObject: ECMAScriptFunctionObject, argumentsList: Arguments) {
|
||||
// 1. Let promiseCapability be ! NewPromiseCapability(%Promise%).
|
||||
const promiseCapability = X(NewPromiseCapability(surroundingAgent.intrinsic('%Promise%')));
|
||||
// 2. Let declResult be FunctionDeclarationInstantiation(functionObject, argumentsList).
|
||||
const declResult = EnsureCompletion(yield* FunctionDeclarationInstantiation(functionObject, argumentsList));
|
||||
// 3. If declResult is not an abrupt completion, then
|
||||
if (declResult.Type === 'normal') {
|
||||
// a. Perform ! AsyncFunctionStart(promiseCapability, ExpressionBody).
|
||||
X(yield* AsyncFunctionStart(promiseCapability, ExpressionBody));
|
||||
} else { // 4. Else
|
||||
// a. Perform ! Call(promiseCapability.[[Reject]], undefined, « declResult.[[Value]] »).
|
||||
X(yield* Call(promiseCapability.Reject, Value.undefined, [declResult.Value!]));
|
||||
}
|
||||
// 5. Return Completion { [[Type]]: return, [[Value]]: promiseCapability.[[Promise]], [[Target]]: empty }.
|
||||
return new Completion({ Type: 'return', Value: promiseCapability.Promise, Target: undefined });
|
||||
}
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-generator-function-definitions-runtime-semantics-evaluatebody */
|
||||
// GeneratorBody : FunctionBody
|
||||
export function* EvaluateBody_GeneratorBody(GeneratorBody: ParseNode.GeneratorBody, functionObject: ECMAScriptFunctionObject, argumentsList: Arguments): StatementEvaluator {
|
||||
// 1. Perform ? FunctionDeclarationInstantiation(functionObject, argumentsList).
|
||||
Q(yield* FunctionDeclarationInstantiation(functionObject, argumentsList));
|
||||
// 2. Let G be ? OrdinaryCreateFromConstructor(functionObject, "%GeneratorPrototype%", « [[GeneratorState]], [[GeneratorContext]], [[GeneratorBrand]] »).
|
||||
const G = Q(yield* OrdinaryCreateFromConstructor(functionObject, '%GeneratorFunction.prototype.prototype%', ['GeneratorState', 'GeneratorContext', 'GeneratorBrand'])) as Mutable<GeneratorObject>;
|
||||
// 3. Set G.[[GeneratorBrand]] to empty.
|
||||
G.GeneratorBrand = undefined;
|
||||
// 4. Set G.[[GeneratorState]] to suspended-start.
|
||||
G.GeneratorState = 'suspendedStart';
|
||||
// 5. Perform GeneratorStart(G, FunctionBody).
|
||||
GeneratorStart(G, GeneratorBody);
|
||||
// 6. Return ReturnCompletion(G).
|
||||
return ReturnCompletion(G);
|
||||
}
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-asyncgenerator-definitions-evaluatebody */
|
||||
// AsyncGeneratorBody : FunctionBody
|
||||
export function* EvaluateBody_AsyncGeneratorBody(FunctionBody: ParseNode.AsyncGeneratorBody, functionObject: ECMAScriptFunctionObject, argumentsList: Arguments): StatementEvaluator {
|
||||
// 1. Perform ? FunctionDeclarationInstantiation(functionObject, argumentsList).
|
||||
Q(yield* FunctionDeclarationInstantiation(functionObject, argumentsList));
|
||||
// 2. Let generator be ? OrdinaryCreateFromConstructor(functionObject, "%AsyncGeneratorFunction.prototype.prototype%", « [[AsyncGeneratorState]], [[AsyncGeneratorContext]], [[AsyncGeneratorQueue]], [[GeneratorBrand]] »).
|
||||
const generator = Q(yield* OrdinaryCreateFromConstructor(functionObject, '%AsyncGeneratorFunction.prototype.prototype%', [
|
||||
'AsyncGeneratorState',
|
||||
'AsyncGeneratorContext',
|
||||
'AsyncGeneratorQueue',
|
||||
'GeneratorBrand',
|
||||
])) as Mutable<AsyncGeneratorObject>;
|
||||
// 3. Set generator.[[GeneratorBrand]] to empty.
|
||||
generator.GeneratorBrand = undefined;
|
||||
generator.AsyncGeneratorState = 'suspendedStart';
|
||||
// 4. Perform ! AsyncGeneratorStart(generator, FunctionBody).
|
||||
X(AsyncGeneratorStart(generator, FunctionBody));
|
||||
// 5. Return Completion { [[Type]]: return, [[Value]]: generator, [[Target]]: empty }.
|
||||
return new Completion({ Type: 'return', Value: generator, Target: undefined });
|
||||
}
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-async-function-definitions-EvaluateBody */
|
||||
// AsyncBody : FunctionBody
|
||||
export function* EvaluateBody_AsyncFunctionBody(FunctionBody: ParseNode.AsyncBody, functionObject: ECMAScriptFunctionObject, argumentsList: Arguments) {
|
||||
// 1. Let promiseCapability be ! NewPromiseCapability(%Promise%).
|
||||
const promiseCapability = X(NewPromiseCapability(surroundingAgent.intrinsic('%Promise%')));
|
||||
// 2. Let declResult be FunctionDeclarationInstantiation(functionObject, argumentsList).
|
||||
const declResult = yield* FunctionDeclarationInstantiation(functionObject, argumentsList);
|
||||
// 3. If declResult is not an abrupt completion, then
|
||||
if (!(declResult instanceof AbruptCompletion)) {
|
||||
// a. Perform ! AsyncFunctionStart(promiseCapability, FunctionBody).
|
||||
X(yield* AsyncFunctionStart(promiseCapability, FunctionBody));
|
||||
} else { // 4. Else,
|
||||
// a. Perform ! Call(promiseCapability.[[Reject]], undefined, « declResult.[[Value]] »).
|
||||
X(yield* Call(promiseCapability.Reject, Value.undefined, [declResult.Value!]));
|
||||
}
|
||||
// 5. Return Completion { [[Type]]: return, [[Value]]: promiseCapability.[[Promise]], [[Target]]: empty }.
|
||||
return new Completion({ Type: 'return', Value: promiseCapability.Promise, Target: undefined });
|
||||
}
|
||||
|
||||
// Initializer :
|
||||
// `=` AssignmentExpression
|
||||
export function* EvaluateBody_AssignmentExpression(AssignmentExpression: ParseNode.Initializer, functionObject: ECMAScriptFunctionObject, argumentsList: Arguments): StatementEvaluator {
|
||||
// 1. Assert: argumentsList is empty.
|
||||
if (surroundingAgent.feature('decorators') && surroundingAgent.feature('decorators.no-bugfix.1')) {
|
||||
// TODO(decorator): spec bug
|
||||
// eslint-disable-next-line no-console
|
||||
console.assert(argumentsList.length === 0, 'Assert: argumentsList is empty.');
|
||||
} else {
|
||||
Assert(argumentsList.length === 0);
|
||||
}
|
||||
// 2. Assert: functionObject.[[ClassFieldInitializerName]] is not empty.
|
||||
Assert(functionObject.ClassFieldInitializerName !== undefined);
|
||||
let value;
|
||||
// 3. If IsAnonymousFunctionDefinition(AssignmentExpression) is true, then
|
||||
if (IsAnonymousFunctionDefinition(AssignmentExpression)) {
|
||||
// a. Let value be NamedEvaluation of Initializer with argument functionObject.[[ClassFieldInitializerName]].
|
||||
value = yield* NamedEvaluation(AssignmentExpression as FunctionDeclaration, functionObject.ClassFieldInitializerName);
|
||||
} else { // 4. Else,
|
||||
// a. Let rhs be the result of evaluating AssignmentExpression.
|
||||
const rhs = Q(yield* Evaluate(AssignmentExpression));
|
||||
// b. Let value be ? GetValue(rhs).
|
||||
value = Q(yield* GetValue(rhs));
|
||||
}
|
||||
// 5. Return Completion { [[Type]]: return, [[Value]]: value, [[Target]]: empty }.
|
||||
return new Completion({ Type: 'return', Value: X(value), Target: undefined });
|
||||
}
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-runtime-semantics-evaluateclassstaticblockbody */
|
||||
// ClassStaticBlockBody : ClassStaticBlockStatementList
|
||||
function* EvaluateClassStaticBlockBody({ ClassStaticBlockStatementList }: ParseNode.ClassStaticBlockBody, functionObject: ECMAScriptFunctionObject) {
|
||||
// 1. Perform ? FunctionDeclarationInstantiation(functionObject, « »).
|
||||
Q(yield* FunctionDeclarationInstantiation(functionObject, []));
|
||||
// 2. Return the result of evaluating ClassStaticBlockStatementList.
|
||||
return yield* Evaluate_FunctionStatementList(ClassStaticBlockStatementList);
|
||||
}
|
||||
|
||||
// FunctionBody : FunctionStatementList
|
||||
// ConciseBody : ExpressionBody
|
||||
// GeneratorBody : FunctionBody
|
||||
// AsyncGeneratorBody : FunctionBody
|
||||
// AsyncBody : FunctionBody
|
||||
// AsyncConciseBody : ExpressionBody
|
||||
// ClassStaticBlockBody : ClassStaticBlockStatementList
|
||||
export function EvaluateBody(Body: Body, functionObject: ECMAScriptFunctionObject, argumentsList: Arguments) {
|
||||
switch (Body.type) {
|
||||
case 'FunctionBody':
|
||||
return EvaluateBody_FunctionBody(Body, functionObject, argumentsList);
|
||||
case 'ConciseBody':
|
||||
return EvaluateBody_ConciseBody(Body, functionObject, argumentsList);
|
||||
case 'GeneratorBody':
|
||||
return EvaluateBody_GeneratorBody(Body, functionObject, argumentsList);
|
||||
case 'AsyncGeneratorBody':
|
||||
return EvaluateBody_AsyncGeneratorBody(Body, functionObject, argumentsList);
|
||||
case 'AsyncBody':
|
||||
return EvaluateBody_AsyncFunctionBody(Body, functionObject, argumentsList);
|
||||
case 'AsyncConciseBody':
|
||||
return EvaluateBody_AsyncConciseBody(Body, functionObject, argumentsList);
|
||||
case 'ClassStaticBlockBody':
|
||||
return EvaluateClassStaticBlockBody(Body, functionObject);
|
||||
default:
|
||||
return EvaluateBody_AssignmentExpression(Body, functionObject, argumentsList);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
import { surroundingAgent } from '../host-defined/engine.mts';
|
||||
import {
|
||||
ObjectValue, Value, ReferenceRecord,
|
||||
} from '../value.mts';
|
||||
import { Q, Completion, AbruptCompletion } from '../completion.mts';
|
||||
import type { ParseNode } from '../parser/ParseNode.mts';
|
||||
import { ArgumentListEvaluation } from './all.mts';
|
||||
import {
|
||||
Assert,
|
||||
IsPropertyReference,
|
||||
IsCallable,
|
||||
GetThisValue,
|
||||
PrepareForTailCall,
|
||||
Call,
|
||||
EnvironmentRecord,
|
||||
} from '#self';
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-evaluatecall */
|
||||
export function* EvaluateCall(func: Value, ref: ReferenceRecord | Value, args: ParseNode | ParseNode.Arguments, tailPosition: boolean) {
|
||||
// 1. If Type(ref) is Reference, then
|
||||
let thisValue;
|
||||
if (ref instanceof ReferenceRecord) {
|
||||
// a. If IsPropertyReference(ref) is true, then
|
||||
if (IsPropertyReference(ref) === Value.true) {
|
||||
// i. Let thisValue be GetThisValue(ref).
|
||||
thisValue = GetThisValue(ref);
|
||||
} else {
|
||||
// i. Let refEnv be ref.[[Base]].
|
||||
const refEnv = ref.Base;
|
||||
// ii. Assert: refEnv is an Environment Record.
|
||||
Assert(refEnv instanceof EnvironmentRecord);
|
||||
// iii. Let thisValue be refEnv.WithBaseObject().
|
||||
thisValue = refEnv.WithBaseObject();
|
||||
}
|
||||
} else {
|
||||
// a. Let thisValue be undefined.
|
||||
thisValue = Value.undefined;
|
||||
}
|
||||
// 3. Let argList be ? ArgumentListEvaluation of arguments.
|
||||
const argList = Q(yield* ArgumentListEvaluation(args));
|
||||
// 4. If Type(func) is not Object, throw a TypeError exception.
|
||||
if (!(func instanceof ObjectValue)) {
|
||||
return surroundingAgent.Throw('TypeError', 'NotAFunction', func);
|
||||
}
|
||||
// 5. If IsCallable(func) is false, throw a TypeError exception.
|
||||
if (!IsCallable(func)) {
|
||||
return surroundingAgent.Throw('TypeError', 'NotAFunction', func);
|
||||
}
|
||||
// 6. If tailPosition is true, perform PrepareForTailCall().
|
||||
if (tailPosition) {
|
||||
PrepareForTailCall();
|
||||
}
|
||||
// 7. Let result be Call(func, thisValue, argList).
|
||||
const result = yield* Call(func, thisValue, argList);
|
||||
// 8. Assert: If tailPosition is true, the above call will not return here but instead
|
||||
// evaluation will continue as if the following return has already occurred.
|
||||
// 9. Assert: If result is not an abrupt completion, then Type(result) is an ECMAScript language type.
|
||||
if (!(result instanceof AbruptCompletion)) {
|
||||
Assert(result instanceof Value || result instanceof Completion);
|
||||
}
|
||||
// 10. Return result.
|
||||
return result;
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
import { Value, ReferenceRecord } from '../value.mts';
|
||||
import { Evaluate, type ReferenceEvaluator } from '../evaluator.mts';
|
||||
import { StringValue } from '../static-semantics/all.mts';
|
||||
import { Q, type PlainCompletion } from '../completion.mts';
|
||||
import type { ParseNode } from '../parser/ParseNode.mts';
|
||||
import {
|
||||
GetValue,
|
||||
Assert,
|
||||
} from '#self';
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-evaluate-expression-key-property-access */
|
||||
export function* EvaluatePropertyAccessWithExpressionKey(baseValue: Value, expression: ParseNode.Expression, strict: boolean): ReferenceEvaluator {
|
||||
// 1. Let propertyNameReference be the result of evaluating expression.
|
||||
const propertyNameReference = Q(yield* Evaluate(expression));
|
||||
// 2. Let propertyNameValue be ? GetValue(propertyNameReference).
|
||||
const propertyNameValue = Q(yield* GetValue(propertyNameReference));
|
||||
// 3. Return the Reference Record { [[Base]]: bv, [[ReferencedName]]: propertyKey, [[Strict]]: strict, [[ThisValue]]: empty }.
|
||||
return new ReferenceRecord({
|
||||
Base: baseValue,
|
||||
ReferencedName: propertyNameValue,
|
||||
Strict: strict ? Value.true : Value.false,
|
||||
ThisValue: undefined,
|
||||
});
|
||||
}
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-evaluate-identifier-key-property-access */
|
||||
export function EvaluatePropertyAccessWithIdentifierKey(baseValue: Value, identifierName: ParseNode.IdentifierName, strict: boolean): PlainCompletion<ReferenceRecord> {
|
||||
// 1. Assert: identifierName is an IdentifierName.
|
||||
Assert(identifierName.type === 'IdentifierName');
|
||||
// 3. Let propertyNameString be StringValue of IdentifierName
|
||||
const propertyNameString = StringValue(identifierName);
|
||||
// 4. Return the Reference Record { [[Base]]: bv, [[ReferencedName]]: propertyNameString, [[Strict]]: strict, [[ThisValue]]: empty }.
|
||||
return new ReferenceRecord({
|
||||
Base: baseValue,
|
||||
ReferencedName: propertyNameString,
|
||||
Strict: strict ? Value.true : Value.false,
|
||||
ThisValue: undefined,
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
import { Evaluate, type ValueEvaluator } from '../evaluator.mts';
|
||||
import { Q } from '../completion.mts';
|
||||
import type { ParseNode } from '../parser/ParseNode.mts';
|
||||
import { ApplyStringOrNumericBinaryOperator, type BinaryOperator } from './all.mts';
|
||||
import { GetValue } from '#self';
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-evaluatestringornumericbinaryexpression */
|
||||
export function* EvaluateStringOrNumericBinaryExpression(leftOperand: ParseNode.Expression, opText: BinaryOperator, rightOperand: ParseNode.Expression): ValueEvaluator {
|
||||
// 1. Let lref be the result of evaluating leftOperand.
|
||||
const lref = Q(yield* Evaluate(leftOperand));
|
||||
// 2. Let lval be ? GetValue(lref).
|
||||
const lval = Q(yield* GetValue(lref));
|
||||
// 3. Let rref be the result of evaluating rightOperand.
|
||||
const rref = Q(yield* Evaluate(rightOperand));
|
||||
// 4. Let rval be ? GetValue(rref).
|
||||
const rval = Q(yield* GetValue(rref));
|
||||
// 5. Return ? ApplyStringOrNumericBinaryOperator(lval, opText, rval).
|
||||
return Q(yield* ApplyStringOrNumericBinaryOperator(lval, opText, rval));
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
import { Q } from '../completion.mts';
|
||||
import type { ValueEvaluator } from '../evaluator.mts';
|
||||
import type { ParseNode } from '../parser/ParseNode.mts';
|
||||
import { EvaluateStringOrNumericBinaryExpression } from './all.mts';
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-exp-operator-runtime-semantics-evaluation */
|
||||
// ExponentiationExpression : UpdateExpression ** ExponentiationExpression
|
||||
export function* Evaluate_ExponentiationExpression({ UpdateExpression, ExponentiationExpression }: ParseNode.ExponentiationExpression): ValueEvaluator {
|
||||
// 1. Return ? EvaluateStringOrNumericBinaryExpression(UpdateExpression, **, ExponentiationExpression).
|
||||
return Q(yield* EvaluateStringOrNumericBinaryExpression(UpdateExpression, '**', ExponentiationExpression));
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
import { surroundingAgent } from '../host-defined/engine.mts';
|
||||
import { Value } from '../value.mts';
|
||||
import { Evaluate } from '../evaluator.mts';
|
||||
import { BoundNames, IsAnonymousFunctionDefinition } from '../static-semantics/all.mts';
|
||||
import { NormalCompletion, Q } from '../completion.mts';
|
||||
import { OutOfRange } from '../helpers.mts';
|
||||
import type { ParseNode } from '../parser/ParseNode.mts';
|
||||
import {
|
||||
NamedEvaluation,
|
||||
InitializeBoundName,
|
||||
BindingClassDeclarationEvaluation,
|
||||
DecoratorListEvaluation,
|
||||
} from './all.mts';
|
||||
import {
|
||||
Assert, GetValue, type ECMAScriptFunctionObject, type FunctionDeclaration,
|
||||
} from '#self';
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-exports-runtime-semantics-evaluation */
|
||||
// ExportDeclaration :
|
||||
// `export` ExportFromClause FromClause `;`
|
||||
// `export` NamedExports `;`
|
||||
// `export` VariableDeclaration
|
||||
// `export` Declaration
|
||||
// `export` `default` HoistableDeclaration
|
||||
// `export` `default` ClassDeclaration
|
||||
// `export` `default` AssignmentExpression `;`
|
||||
export function* Evaluate_ExportDeclaration(ExportDeclaration: ParseNode.ExportDeclaration) {
|
||||
const {
|
||||
FromClause, NamedExports,
|
||||
VariableStatement,
|
||||
Declaration,
|
||||
default: isDefault,
|
||||
HoistableDeclaration,
|
||||
ClassDeclaration,
|
||||
AssignmentExpression,
|
||||
Decorators,
|
||||
} = ExportDeclaration;
|
||||
|
||||
if (FromClause || NamedExports) {
|
||||
// 1. Return NormalCompletion(empty).
|
||||
return NormalCompletion(undefined);
|
||||
}
|
||||
if (VariableStatement) {
|
||||
// 1. Return the result of evaluating VariableStatement.
|
||||
return yield* Evaluate(VariableStatement);
|
||||
}
|
||||
if (Declaration) {
|
||||
if (Decorators) {
|
||||
Assert(Declaration.type === 'ClassDeclaration' && !Declaration.Decorators);
|
||||
const decorators = Q(yield* DecoratorListEvaluation(Decorators));
|
||||
Q(yield* BindingClassDeclarationEvaluation(Declaration, decorators));
|
||||
return undefined;
|
||||
} else {
|
||||
// 1. Return the result of evaluating Declaration.
|
||||
return yield* Evaluate(ExportDeclaration.Declaration!);
|
||||
}
|
||||
}
|
||||
if (!isDefault) {
|
||||
throw new OutOfRange('Evaluate_ExportDeclaration', ExportDeclaration);
|
||||
}
|
||||
if (HoistableDeclaration) {
|
||||
// 1. Return the result of evaluating HoistableDeclaration.
|
||||
return yield* Evaluate(HoistableDeclaration);
|
||||
}
|
||||
if (ClassDeclaration) {
|
||||
const decorators = Decorators ? Q(yield* DecoratorListEvaluation(Decorators)) : [];
|
||||
const value = Q(yield* BindingClassDeclarationEvaluation(ClassDeclaration, decorators)) as ECMAScriptFunctionObject;
|
||||
// 2. Let className be the sole element of BoundNames of ClassDeclaration.
|
||||
const className = BoundNames(ClassDeclaration)[0];
|
||||
// If className is "*default*", then
|
||||
if (className.stringValue() === '*default*') {
|
||||
// a. Let env be the running execution context's LexicalEnvironment.
|
||||
const env = surroundingAgent.runningExecutionContext.LexicalEnvironment;
|
||||
// b. Perform ? InitializeBoundName("*default*", value, env).
|
||||
Q(yield* InitializeBoundName(Value('*default*'), value, env));
|
||||
}
|
||||
// 3. Return NormalCompletion(empty).
|
||||
return NormalCompletion(undefined);
|
||||
}
|
||||
if (AssignmentExpression) {
|
||||
let value;
|
||||
// 1. If IsAnonymousFunctionDefinition(AssignmentExpression) is true, then
|
||||
if (IsAnonymousFunctionDefinition(AssignmentExpression)) {
|
||||
// a. Let value be NamedEvaluation of AssignmentExpression with argument "default".
|
||||
value = yield* NamedEvaluation(AssignmentExpression as FunctionDeclaration, Value('default'));
|
||||
} else { // 2. Else,
|
||||
// a. Let rhs be the result of evaluating AssignmentExpression.
|
||||
const rhs = Q(yield* Evaluate(AssignmentExpression));
|
||||
// a. Let value be ? GetValue(rhs).
|
||||
value = Q(yield* GetValue(rhs));
|
||||
}
|
||||
// 3. Let env be the running execution context's LexicalEnvironment.
|
||||
const env = surroundingAgent.runningExecutionContext.LexicalEnvironment;
|
||||
// 4. Perform ? InitializeBoundName("*default*", value, env).
|
||||
Q(yield* InitializeBoundName(Value('*default*'), value as ECMAScriptFunctionObject, env));
|
||||
// 5. Return NormalCompletion(empty).
|
||||
return NormalCompletion(undefined);
|
||||
}
|
||||
throw new OutOfRange('Evaluate_ExportDeclaration', ExportDeclaration);
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
import { Evaluate, type ValueEvaluator } from '../evaluator.mts';
|
||||
import { Q } from '../completion.mts';
|
||||
import type { ParseNode } from '../parser/ParseNode.mts';
|
||||
import { GetValue } from '#self';
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-expression-statement-runtime-semantics-evaluation */
|
||||
// ExpressionStatement :
|
||||
// Expression `;`
|
||||
export function* Evaluate_ExpressionStatement({ Expression }: ParseNode.ExpressionStatement): ValueEvaluator {
|
||||
// 1. Let exprRef be the result of evaluating Expression.
|
||||
const exprRef = Q(yield* Evaluate(Expression));
|
||||
// 2. Return ? GetValue(exprRef).
|
||||
return Q(yield* GetValue(exprRef));
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
import { NormalCompletion } from '../completion.mts';
|
||||
import type { ParseNode } from '../parser/ParseNode.mts';
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-function-definitions-runtime-semantics-evaluation */
|
||||
// FunctionDeclaration :
|
||||
// function BindingIdentifier ( FormalParameters ) { FunctionBody }
|
||||
// function ( FormalParameters ) { FunctionBody }
|
||||
export function Evaluate_FunctionDeclaration(_FunctionDeclaration: ParseNode.FunctionDeclaration) {
|
||||
// 1. Return NormalCompletion(empty).
|
||||
return NormalCompletion(undefined);
|
||||
}
|
||||
@@ -0,0 +1,274 @@
|
||||
import { surroundingAgent } from '../host-defined/engine.mts';
|
||||
import { Value, type Arguments } from '../value.mts';
|
||||
import {
|
||||
BoundNames,
|
||||
IsConstantDeclaration,
|
||||
IsSimpleParameterList,
|
||||
ContainsExpression,
|
||||
VarDeclaredNames,
|
||||
VarScopedDeclarations,
|
||||
LexicallyDeclaredNames,
|
||||
LexicallyScopedDeclarations,
|
||||
} from '../static-semantics/all.mts';
|
||||
import { Q, X, NormalCompletion } from '../completion.mts';
|
||||
import { JSStringSet } from '../helpers.mts';
|
||||
import type { PlainEvaluator } from '../evaluator.mts';
|
||||
import {
|
||||
InstantiateFunctionObject,
|
||||
IteratorBindingInitialization_FormalParameters,
|
||||
} from './all.mts';
|
||||
import {
|
||||
Assert,
|
||||
CreateListIteratorRecord,
|
||||
CreateMappedArgumentsObject,
|
||||
CreateUnmappedArgumentsObject,
|
||||
type ECMAScriptFunctionObject,
|
||||
} from '#self';
|
||||
import { DeclarativeEnvironmentRecord } from '#self';
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-functiondeclarationinstantiation */
|
||||
export function* FunctionDeclarationInstantiation(func: ECMAScriptFunctionObject, argumentsList: Arguments): PlainEvaluator<void> {
|
||||
// 1. Let calleeContext be the running execution context.
|
||||
const calleeContext = surroundingAgent.runningExecutionContext;
|
||||
// 2. Let code be func.[[ECMAScriptCode]].
|
||||
const code = func.ECMAScriptCode!;
|
||||
// 3. Let strict be func.[[Strict]].
|
||||
const strict = func.Strict;
|
||||
// 4. Let formals be func.[[FormalParameters]].
|
||||
const formals = func.FormalParameters;
|
||||
// 5. Let parameterNames be BoundNames of formals.
|
||||
const parameterNames = BoundNames(formals);
|
||||
// 6. If parameterNames has any duplicate entries, let hasDuplicates be true. Otherwise, let hasDuplicates be false.
|
||||
const hasDuplicates = new JSStringSet(parameterNames).size !== parameterNames.length;
|
||||
// 7. Let simpleParameterList be IsSimpleParameterList of formals.
|
||||
const simpleParameterList = IsSimpleParameterList(formals);
|
||||
// 8. Let hasParameterExpressions be ContainsExpression of formals.
|
||||
const hasParameterExpressions = ContainsExpression(formals);
|
||||
// 9. Let varNames be the VarDeclaredNames of code.
|
||||
const varNames = VarDeclaredNames(code);
|
||||
// 10. Let varDeclarations be the VarScopedDeclarations of code.
|
||||
const varDeclarations = VarScopedDeclarations(code);
|
||||
// 11. Let lexicalNames be the LexicallyDeclaredNames of code.
|
||||
const lexicalNames = new JSStringSet(LexicallyDeclaredNames(code));
|
||||
// 12. Let functionNames be a new empty List.
|
||||
const functionNames = new JSStringSet();
|
||||
// 13. Let functionNames be a new empty List.
|
||||
const functionsToInitialize = [];
|
||||
// 14. For each d in varDeclarations, in reverse list order, do
|
||||
for (const d of [...varDeclarations].reverse()) {
|
||||
// a. If d is neither a VariableDeclaration nor a ForBinding nor a BindingIdentifier, then
|
||||
if (d.type !== 'VariableDeclaration'
|
||||
&& d.type !== 'ForBinding'
|
||||
&& d.type !== 'BindingIdentifier') {
|
||||
// i. Assert: d is either a FunctionDeclaration, a GeneratorDeclaration, an AsyncFunctionDeclaration, or an AsyncGeneratorDeclaration.
|
||||
Assert(d.type === 'FunctionDeclaration'
|
||||
|| d.type === 'GeneratorDeclaration'
|
||||
|| d.type === 'AsyncFunctionDeclaration'
|
||||
|| d.type === 'AsyncGeneratorDeclaration');
|
||||
// ii. Let fn be the sole element of the BoundNames of d.
|
||||
const fn = BoundNames(d)[0];
|
||||
// iii. If fn is not an element of functionNames, then
|
||||
if (!functionNames.has(fn)) {
|
||||
// 1. Insert fn as the first element of functionNames.
|
||||
functionNames.add(fn);
|
||||
// 2. NOTE: If there are multiple function declarations for the same name, the last declaration is used.
|
||||
// 3. Insert d as the first element of functionsToInitialize.
|
||||
functionsToInitialize.unshift(d);
|
||||
}
|
||||
}
|
||||
}
|
||||
// 15. Let argumentsObjectNeeded be true.
|
||||
let argumentsObjectNeeded = true;
|
||||
// If func.[[ThisMode]] is lexical, then
|
||||
if (func.ThisMode === 'lexical') {
|
||||
// a. NOTE: Arrow functions never have an arguments objects.
|
||||
// b. Set argumentsObjectNeeded to false.
|
||||
argumentsObjectNeeded = false;
|
||||
} else if (new JSStringSet(parameterNames).has('arguments')) {
|
||||
// a. Set argumentsObjectNeeded to false.
|
||||
argumentsObjectNeeded = false;
|
||||
} else if (hasParameterExpressions === false) {
|
||||
// a. If "arguments" is an element of functionNames or if "arguments" is an element of lexicalNames, then
|
||||
if (functionNames.has('arguments') || lexicalNames.has('arguments')) {
|
||||
// i. Set argumentsObjectNeeded to false.
|
||||
argumentsObjectNeeded = false;
|
||||
}
|
||||
}
|
||||
let env;
|
||||
// 19. If strict is true or if hasParameterExpressions is false, then
|
||||
if (strict || hasParameterExpressions === false) {
|
||||
// a. NOTE: Only a single lexical environment is needed for the parameters and top-level vars.
|
||||
// b. Let env be the LexicalEnvironment of calleeContext.
|
||||
env = calleeContext.LexicalEnvironment;
|
||||
} else {
|
||||
// a. NOTE: A separate Environment Record is needed to ensure that bindings created by direct eval
|
||||
// calls in the formal parameter list are outside the environment where parameters are declared.
|
||||
// b. Let calleeEnv be the LexicalEnvironment of calleeContext.
|
||||
const calleeEnv = calleeContext.LexicalEnvironment;
|
||||
// c. Let env be NewDeclarativeEnvironment(calleeEnv).
|
||||
env = new DeclarativeEnvironmentRecord(calleeEnv);
|
||||
// d. Assert: The VariableEnvironment of calleeContext is calleeEnv.
|
||||
Assert(calleeContext.VariableEnvironment === calleeEnv);
|
||||
// e. Set the LexicalEnvironment of calleeContext to env.
|
||||
calleeContext.LexicalEnvironment = env;
|
||||
}
|
||||
// 21. For each String paramName in parameterNames, do
|
||||
for (const paramName of parameterNames) {
|
||||
// a. Let alreadyDeclared be env.HasBinding(paramName).
|
||||
const alreadyDeclared = yield* env.HasBinding(paramName);
|
||||
// b. NOTE: Early errors ensure that duplicate parameter names can only occur in
|
||||
// non-strict functions that do not have parameter default values or rest parameters.
|
||||
// c. If alreadyDeclared is false, then
|
||||
if (alreadyDeclared === Value.false) {
|
||||
// i. Perform ! env.CreateMutableBinding(paramName, false).
|
||||
X(env.CreateMutableBinding(paramName, Value.false));
|
||||
// ii. If hasDuplicates is true, then
|
||||
if (hasDuplicates === true) {
|
||||
// 1. Perform ! env.InitializeBinding(paramName, undefined).
|
||||
X(env.InitializeBinding(paramName, Value.undefined));
|
||||
}
|
||||
}
|
||||
}
|
||||
// 22. If argumentsObjectNeeded is true, then
|
||||
let parameterBindings: JSStringSet;
|
||||
if (argumentsObjectNeeded === true) {
|
||||
let ao;
|
||||
// a. If strict is true or if simpleParameterList is false, then
|
||||
if (strict || simpleParameterList === false) {
|
||||
// i. Let ao be CreateUnmappedArgumentsObject(argumentsList).
|
||||
ao = CreateUnmappedArgumentsObject(argumentsList);
|
||||
} else {
|
||||
// i. NOTE: mapped argument object is only provided for non-strict functions
|
||||
// that don't have a rest parameter, any parameter default value initializers,
|
||||
// or any destructured parameters.
|
||||
// ii. Let ao be CreateMappedArgumentsObject(func, formals, argumentsList, env).
|
||||
ao = CreateMappedArgumentsObject(func, formals, argumentsList, env);
|
||||
}
|
||||
// c. If strict is true, then
|
||||
if (strict) {
|
||||
// i. Perform ! env.CreateImmutableBinding("arguments", false).
|
||||
X(env.CreateImmutableBinding(Value('arguments'), Value.false));
|
||||
} else {
|
||||
// i. Perform ! env.CreateMutableBinding("arguments", false).
|
||||
X(env.CreateMutableBinding(Value('arguments'), Value.false));
|
||||
}
|
||||
// e. Call env.InitializeBinding("arguments", ao).
|
||||
yield* env.InitializeBinding(Value('arguments'), ao);
|
||||
// f. Let parameterBindings be a new List of parameterNames with "arguments" appended.
|
||||
parameterBindings = new JSStringSet(parameterNames);
|
||||
parameterBindings.add('arguments');
|
||||
} else {
|
||||
// a. Let parameterBindings be parameterNames.
|
||||
parameterBindings = new JSStringSet(parameterNames);
|
||||
}
|
||||
// 24. Let iteratorRecord be CreateListIteratorRecord(argumentsList).
|
||||
const iteratorRecord = CreateListIteratorRecord(argumentsList.values());
|
||||
let usedEnv;
|
||||
// 25. If hasDuplicates is true, then
|
||||
if (hasDuplicates) {
|
||||
usedEnv = Value.undefined;
|
||||
} else {
|
||||
usedEnv = env;
|
||||
}
|
||||
// 1. NOTE: The following step cannot return a ReturnCompletion because the only way such a completion can arise in expression position is by use of |YieldExpression|, which is forbidden in parameter lists by Early Error rules in <emu-xref href="#sec-generator-function-definitions-static-semantics-early-errors"></emu-xref> and <emu-xref href="#sec-async-generator-function-definitions-static-semantics-early-errors"></emu-xref>.
|
||||
// Perform ? IteratorBindingInitialization of _formals_ with arguments _iteratorRecord_ and _usedEnv_.
|
||||
Q(yield* IteratorBindingInitialization_FormalParameters(formals, iteratorRecord, usedEnv));
|
||||
let varEnv;
|
||||
// 27. If hasParameterExpressions is false, then
|
||||
if (hasParameterExpressions === false) {
|
||||
// a. NOTE: Only a single lexical environment is needed for the parameters and top-level vars.
|
||||
// b. Let instantiatedVarNames be a copy of the List parameterBindings.
|
||||
const instantiatedVarNames = new JSStringSet(parameterBindings);
|
||||
// c. For each n in varNames, do
|
||||
for (const n of varNames) {
|
||||
// i. If n is not an element of instantiatedVarNames, then
|
||||
if (!instantiatedVarNames.has(n)) {
|
||||
// 1. Append n to instantiatedVarNames.
|
||||
instantiatedVarNames.add(n);
|
||||
// 2. Perform ! env.CreateMutableBinding(n, false).
|
||||
X(env.CreateMutableBinding(n, Value.false));
|
||||
// 3. Call env.InitializeBinding(n, undefined).
|
||||
yield* env.InitializeBinding(n, Value.undefined);
|
||||
}
|
||||
}
|
||||
// d. Let varEnv be env.
|
||||
varEnv = env;
|
||||
} else {
|
||||
// a. NOTE: A separate Environment Record is needed to ensure that closures created by expressions
|
||||
// in the formal parameter list do not have visibility of declarations in the function body.
|
||||
// b. Let varEnv be NewDeclarativeEnvironment(env).
|
||||
varEnv = new DeclarativeEnvironmentRecord(env);
|
||||
// c. Set the VariableEnvironment of calleeContext to varEnv.
|
||||
calleeContext.VariableEnvironment = varEnv;
|
||||
// d. Let instantiatedVarNames be a new empty List.
|
||||
const instantiatedVarNames = new JSStringSet();
|
||||
// e. For each n in varNames, do
|
||||
for (const n of varNames) {
|
||||
// If n is not an element of instantiatedVarNames, then
|
||||
if (!instantiatedVarNames.has(n)) {
|
||||
// 1. Append n to instantiatedVarNames.
|
||||
instantiatedVarNames.add(n);
|
||||
// 2. Perform ! varEnv.CreateMutableBinding(n, false).
|
||||
X(varEnv.CreateMutableBinding(n, Value.false));
|
||||
let initialValue;
|
||||
// 3. If n is not an element of parameterBindings or if n is an element of functionNames, let initialValue be undefined.
|
||||
if (!parameterBindings.has(n) || functionNames.has(n)) {
|
||||
initialValue = Value.undefined;
|
||||
} else {
|
||||
// a. Let initialValue be ! env.GetBindingValue(n, false).
|
||||
initialValue = X(env.GetBindingValue(n, Value.false));
|
||||
}
|
||||
// 5. Call varEnv.InitializeBinding(n, initialValue).
|
||||
yield* varEnv.InitializeBinding(n, initialValue);
|
||||
// 6. NOTE: vars whose names are the same as a formal parameter, initially have the same value as the corresponding initialized parameter.
|
||||
}
|
||||
}
|
||||
}
|
||||
// 29. NOTE: Annex B.3.3.1 adds additional steps at this point.
|
||||
let lexEnv;
|
||||
// 30. If strict is false, then
|
||||
if (strict === false) {
|
||||
// a. Let lexEnv be NewDeclarativeEnvironment(varEnv).
|
||||
lexEnv = new DeclarativeEnvironmentRecord(varEnv);
|
||||
// b. NOTE: Non-strict functions use a separate lexical Environment Record for top-level lexical declarations
|
||||
// so that a direct eval can determine whether any var scoped declarations introduced by the eval code
|
||||
// conflict with pre-existing top-level lexically scoped declarations. This is not needed for strict functions
|
||||
// because a strict direct eval always places all declarations into a new Environment Record.
|
||||
} else {
|
||||
// a. Else, let lexEnv be varEnv.
|
||||
lexEnv = varEnv;
|
||||
}
|
||||
// 32. Set the LexicalEnvironment of calleeContext to lexEnv.
|
||||
calleeContext.LexicalEnvironment = lexEnv;
|
||||
// 33. Let lexDeclarations be the LexicallyScopedDeclarations of code.
|
||||
const lexDeclarations = LexicallyScopedDeclarations(code);
|
||||
// 34. For each element d in lexDeclarations, do
|
||||
for (const d of lexDeclarations) {
|
||||
// a. NOTE: A lexically declared name cannot be the same as a function/generator declaration, formal
|
||||
// parameter, or a var name. Lexically declared names are only instantiated here but not initialized.
|
||||
// b. For each element dn of the BoundNames of d, do
|
||||
for (const dn of BoundNames(d)) {
|
||||
// i. If IsConstantDeclaration of d is true, then
|
||||
if (IsConstantDeclaration(d)) {
|
||||
// 1. Perform ! lexEnv.CreateImmutableBinding(dn, true).
|
||||
X(lexEnv.CreateImmutableBinding(dn, Value.true));
|
||||
} else {
|
||||
// 1. Perform ! lexEnv.CreateMutableBinding(dn, false).
|
||||
X(lexEnv.CreateMutableBinding(dn, Value.false));
|
||||
}
|
||||
}
|
||||
}
|
||||
// 35. Let privateEnv be the PrivateEnvironment of calleeContext.
|
||||
const privateEnv = calleeContext.PrivateEnvironment;
|
||||
// 36. For each Parse Node f in functionsToInitialize, do
|
||||
for (const f of functionsToInitialize) {
|
||||
// a. Let fn be the sole element of the BoundNames of f.
|
||||
const fn = BoundNames(f)[0];
|
||||
// b. Let fo be InstantiateFunctionObject of f with argument lexEnv and privateEnv.
|
||||
const fo = InstantiateFunctionObject(f, lexEnv, privateEnv);
|
||||
// c. Perform ! varEnv.SetMutableBinding(fn, fo, false).
|
||||
X(varEnv.SetMutableBinding(fn, fo, Value.false));
|
||||
}
|
||||
// 37. Return NormalCompletion(empty).
|
||||
return NormalCompletion(undefined);
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
import type { ParseNode } from '../parser/ParseNode.mts';
|
||||
import { InstantiateOrdinaryFunctionExpression } from './all.mts';
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-function-definitions-runtime-semantics-evaluation */
|
||||
// FunctionExpression :
|
||||
// `function` `(` FormalParameters `)` `{` FunctionBody `}`
|
||||
// `function` BindingIdentifier `(` FormalParameters `)` `{` FunctionBody `}`
|
||||
export function Evaluate_FunctionExpression(FunctionExpression: ParseNode.FunctionExpression) {
|
||||
// 1. Return InstantiateOrdinaryFunctionExpression of FunctionExpression.
|
||||
return InstantiateOrdinaryFunctionExpression(FunctionExpression);
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
import type { ParseNode } from '../parser/ParseNode.mts';
|
||||
import { Evaluate_StatementList } from './all.mts';
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-function-definitions-runtime-semantics-evaluation */
|
||||
// FunctionStatementList : [empty]
|
||||
//
|
||||
// (implicit)
|
||||
// FunctionStatementList : StatementList
|
||||
export function Evaluate_FunctionStatementList(FunctionStatementList: ParseNode.FunctionStatementList) {
|
||||
return Evaluate_StatementList(FunctionStatementList);
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
import type { ParseNode } from '../parser/ParseNode.mts';
|
||||
import { InstantiateGeneratorFunctionExpression } from './all.mts';
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-generator-function-definitions-runtime-semantics-evaluation */
|
||||
// GeneratorExpression :
|
||||
// `function` `*` `(` FormalParameters `)` `{` GeneratorBody `}`
|
||||
// `function` `*` BindingIdentifier `(` FormalParameters `)` `{` GeneratorBody `}`
|
||||
export function Evaluate_GeneratorExpression(GeneratorExpression: ParseNode.GeneratorExpression) {
|
||||
// 1. Return InstantiateGeneratorFunctionExpression of GeneratorExpression.
|
||||
return InstantiateGeneratorFunctionExpression(GeneratorExpression);
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
import {
|
||||
ObjectValue, UndefinedValue, JSStringValue, Value,
|
||||
} from '../value.mts';
|
||||
import { Q } from '../completion.mts';
|
||||
import type { ValueEvaluator } from '../evaluator.mts';
|
||||
import {
|
||||
Assert,
|
||||
Get,
|
||||
ToString,
|
||||
surroundingAgent,
|
||||
} from '#self';
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-getsubstitution */
|
||||
export function* GetSubstitution(matched: JSStringValue, str: JSStringValue, position: number, captures: readonly (JSStringValue | UndefinedValue)[], namedCaptures: UndefinedValue | ObjectValue, replacementTemplate: JSStringValue): ValueEvaluator<JSStringValue> {
|
||||
const stringLength = str.stringValue().length;
|
||||
Assert(position <= stringLength);
|
||||
const result: string[] = [];
|
||||
let templateRemainder = replacementTemplate.stringValue();
|
||||
let ref: string;
|
||||
let refReplacement: string;
|
||||
while (templateRemainder.length) {
|
||||
if (templateRemainder.startsWith('$$')) {
|
||||
ref = '$$';
|
||||
refReplacement = '$';
|
||||
} else if (templateRemainder.startsWith('$`')) {
|
||||
ref = '$`';
|
||||
refReplacement = str.stringValue().slice(0, position);
|
||||
} else if (templateRemainder.startsWith('$&')) {
|
||||
ref = '$&';
|
||||
refReplacement = matched.stringValue();
|
||||
} else if (templateRemainder.startsWith("$'")) {
|
||||
ref = "$'";
|
||||
const matchLength = matched.stringValue().length;
|
||||
const tailPos = position + matchLength;
|
||||
refReplacement = str.stringValue().slice(Math.min(tailPos, stringLength));
|
||||
} else if (templateRemainder.match(/^\$\d+/)) {
|
||||
let digitCount = templateRemainder.match(/^\$\d\d/) ? 2 : 1;
|
||||
let digits = templateRemainder.slice(1, 1 + digitCount);
|
||||
let index = parseInt(digits, 10);
|
||||
Assert(index >= 0 && index <= 99);
|
||||
const captureLen = captures.length;
|
||||
if (index > captureLen && digitCount === 2) {
|
||||
digitCount = 1;
|
||||
digits = digits[0];
|
||||
index = parseInt(digits, 10);
|
||||
}
|
||||
ref = templateRemainder.slice(0, 1 + digitCount);
|
||||
if (index >= 1 && index <= captureLen) {
|
||||
const capture = captures[index - 1];
|
||||
if (capture instanceof UndefinedValue) {
|
||||
refReplacement = '';
|
||||
} else {
|
||||
refReplacement = capture.stringValue();
|
||||
}
|
||||
} else {
|
||||
refReplacement = ref;
|
||||
}
|
||||
} else if (templateRemainder.startsWith('$<')) {
|
||||
const gtPos = templateRemainder.indexOf('>', 0);
|
||||
if (gtPos === -1 || namedCaptures instanceof UndefinedValue) {
|
||||
ref = '$<';
|
||||
refReplacement = ref;
|
||||
} else {
|
||||
ref = templateRemainder.slice(0, gtPos + 1);
|
||||
const groupName = templateRemainder.slice(2, gtPos);
|
||||
Assert(namedCaptures instanceof ObjectValue);
|
||||
const capture = Q(yield* Get(namedCaptures, Value(groupName)));
|
||||
if (capture instanceof UndefinedValue) {
|
||||
refReplacement = '';
|
||||
} else {
|
||||
refReplacement = (Q(yield* ToString(capture))).stringValue();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ref = templateRemainder[0];
|
||||
refReplacement = ref;
|
||||
}
|
||||
const refLength = ref.length;
|
||||
templateRemainder = templateRemainder.slice(refLength);
|
||||
result.push(refReplacement);
|
||||
}
|
||||
let result_str;
|
||||
try {
|
||||
result_str = result.join('');
|
||||
} catch (e) {
|
||||
// test262/test/staging/sm/String/replace-math.js
|
||||
return surroundingAgent.Throw('RangeError', 'OutOfRange', 'String too long');
|
||||
}
|
||||
return Value(result_str);
|
||||
}
|
||||
@@ -0,0 +1,141 @@
|
||||
import { surroundingAgent } from '../host-defined/engine.mts';
|
||||
import {
|
||||
BoundNames,
|
||||
IsConstantDeclaration,
|
||||
LexicallyDeclaredNames,
|
||||
LexicallyScopedDeclarations,
|
||||
VarDeclaredNames,
|
||||
VarScopedDeclarations,
|
||||
} from '../static-semantics/all.mts';
|
||||
import { Value } from '../value.mts';
|
||||
import { Q, NormalCompletion } from '../completion.mts';
|
||||
import { JSStringSet } from '../helpers.mts';
|
||||
import type { ParseNode } from '../parser/ParseNode.mts';
|
||||
import { InstantiateFunctionObject } from './all.mts';
|
||||
import { Assert, GlobalEnvironmentRecord } from '#self';
|
||||
|
||||
export function* GlobalDeclarationInstantiation(script: ParseNode.Script, env: GlobalEnvironmentRecord) {
|
||||
// 2. Let lexNames be the LexicallyDeclaredNames of script.
|
||||
const lexNames = LexicallyDeclaredNames(script);
|
||||
// 3. Let varNames be the VarDeclaredNames of script.
|
||||
const varNames = VarDeclaredNames(script);
|
||||
// 4. For each name in lexNames, do
|
||||
for (const name of lexNames) {
|
||||
// 1. If env.HasLexicalDeclaration(name) is true, throw a SyntaxError exception.
|
||||
if ((yield* env.HasLexicalDeclaration(name)) === Value.true) {
|
||||
return surroundingAgent.Throw('SyntaxError', 'AlreadyDeclared', name);
|
||||
}
|
||||
// 1. Let hasRestrictedGlobal be ? env.HasRestrictedGlobalProperty(name).
|
||||
const hasRestrictedGlobal = Q(yield* env.HasRestrictedGlobalProperty(name));
|
||||
// 1. If hasRestrictedGlobal is true, throw a SyntaxError exception.
|
||||
if (hasRestrictedGlobal === Value.true) {
|
||||
return surroundingAgent.Throw('SyntaxError', 'AlreadyDeclared', name);
|
||||
}
|
||||
}
|
||||
// 5. For each name in varNames, do
|
||||
for (const name of varNames) {
|
||||
// 1. If env.HasLexicalDeclaration(name) is true, throw a SyntaxError exception.
|
||||
if ((yield* env.HasLexicalDeclaration(name)) === Value.true) {
|
||||
return surroundingAgent.Throw('SyntaxError', 'AlreadyDeclared', name);
|
||||
}
|
||||
}
|
||||
// 6. Let varDeclarations be the VarScopedDeclarations of script.
|
||||
const varDeclarations = VarScopedDeclarations(script);
|
||||
// 7. Let functionsToInitialize be a new empty List.
|
||||
const functionsToInitialize = [];
|
||||
// 8. Let declaredFunctionNames be a new empty List.
|
||||
const declaredFunctionNames = new JSStringSet();
|
||||
// 9. For each d in varDeclarations, in reverse list order, do
|
||||
for (const d of [...varDeclarations].reverse()) {
|
||||
// a. If d is neither a VariableDeclaration nor a ForBinding nor a BindingIdentifier, then
|
||||
if (d.type !== 'VariableDeclaration'
|
||||
&& d.type !== 'ForBinding'
|
||||
&& d.type !== 'BindingIdentifier') {
|
||||
// i. Assert: d is either a FunctionDeclaration, a GeneratorDeclaration, an AsyncFunctionDeclaration, or an AsyncGeneratorDeclaration.
|
||||
Assert(d.type === 'FunctionDeclaration'
|
||||
|| d.type === 'GeneratorDeclaration'
|
||||
|| d.type === 'AsyncFunctionDeclaration'
|
||||
|| d.type === 'AsyncGeneratorDeclaration');
|
||||
// ii. NOTE: If there are multiple function declarations for the same name, the last declaration is used.
|
||||
// iii. Let fn be the sole element of the BoundNames of d.
|
||||
const fn = BoundNames(d)[0];
|
||||
// iv. If fn is not an element of declaredFunctionNames, then
|
||||
if (!declaredFunctionNames.has(fn)) {
|
||||
// 1. Let fnDefinable be ? env.CanDeclareGlobalFunction(fn).
|
||||
const fnDefinable = Q(yield* env.CanDeclareGlobalFunction(fn));
|
||||
// 2. If fnDefinable is false, throw a TypeError exception.
|
||||
if (fnDefinable === Value.false) {
|
||||
return surroundingAgent.Throw('TypeError', 'AlreadyDeclared', fn);
|
||||
}
|
||||
// 3. Append fn to declaredFunctionNames.
|
||||
declaredFunctionNames.add(fn);
|
||||
// 4. Insert d as the first element of functionsToInitialize.
|
||||
functionsToInitialize.unshift(d);
|
||||
}
|
||||
}
|
||||
}
|
||||
// 10. Let declaredVarNames be a new empty List.
|
||||
const declaredVarNames = new JSStringSet();
|
||||
// 11. For each d in varDeclarations, do
|
||||
for (const d of varDeclarations) {
|
||||
// a. If d is a VariableDeclaration, a ForBinding, or a BindingIdentifier, then
|
||||
if (d.type === 'VariableDeclaration'
|
||||
|| d.type === 'ForBinding'
|
||||
|| d.type === 'BindingIdentifier') {
|
||||
// i. For each String vn in the BoundNames of d, do
|
||||
for (const vn of BoundNames(d)) {
|
||||
// 1. If vn is not an element of declaredFunctionNames, then
|
||||
if (!declaredFunctionNames.has(vn)) {
|
||||
// a. Let vnDefinable be ? env.CanDeclareGlobalVar(vn).
|
||||
const vnDefinable = Q(yield* env.CanDeclareGlobalVar(vn));
|
||||
// b. If vnDefinable is false, throw a TypeError exception.
|
||||
if (vnDefinable === Value.false) {
|
||||
return surroundingAgent.Throw('TypeError', 'AlreadyDeclared', vn);
|
||||
}
|
||||
// c. If vn is not an element of declaredVarNames, then
|
||||
if (!declaredVarNames.has(vn)) {
|
||||
// i. Append vn to declaredVarNames.
|
||||
declaredVarNames.add(vn);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// 12. NOTE: No abnormal terminations occur after this algorithm step if the global object is an ordinary object. However, if the global object is a Proxy exotic object it may exhibit behaviours that cause abnormal terminations in some of the following steps.
|
||||
// 13. NOTE: Annex B.3.3.2 adds additional steps at this point.
|
||||
// 14. Let lexDeclarations be the LexicallyScopedDeclarations of script.
|
||||
const lexDeclarations = LexicallyScopedDeclarations(script);
|
||||
// 15. Let privateEnv be null.
|
||||
const privateEnv = Value.null;
|
||||
// 16. For each element d in lexDeclarations, do
|
||||
for (const d of lexDeclarations) {
|
||||
// a. NOTE: Lexically declared names are only instantiated here but not initialized.
|
||||
// b. For each element dn of the BoundNames of d, do
|
||||
for (const dn of BoundNames(d)) {
|
||||
// 1. If IsConstantDeclaration of d is true, then
|
||||
if (IsConstantDeclaration(d)) {
|
||||
// 1. Perform ? env.CreateImmutableBinding(dn, true).
|
||||
Q(env.CreateImmutableBinding(dn, Value.true));
|
||||
} else { // 1. Else,
|
||||
// 1. Perform ? env.CreateMutableBinding(dn, false).
|
||||
Q(yield* env.CreateMutableBinding(dn, Value.false));
|
||||
}
|
||||
}
|
||||
}
|
||||
// 17. For each Parse Node f in functionsToInitialize, do
|
||||
for (const f of functionsToInitialize) {
|
||||
// a. Let fn be the sole element of the BoundNames of f.
|
||||
const fn = BoundNames(f)[0];
|
||||
// b. Let fo be InstantiateFunctionObject of f with argument env and privateEnv.
|
||||
const fo = InstantiateFunctionObject(f, env, privateEnv);
|
||||
// c. Perform ? env.CreateGlobalFunctionBinding(fn, fo, false).
|
||||
Q(yield* env.CreateGlobalFunctionBinding(fn, fo, Value.false));
|
||||
}
|
||||
// 18. For each String vn in declaredVarNames, in list order, do
|
||||
for (const vn of declaredVarNames) {
|
||||
// a. Perform ? env.CreateGlobalVarBinding(vn, false).
|
||||
Q(yield* env.CreateGlobalVarBinding(vn, Value.false));
|
||||
}
|
||||
// 19. Return NormalCompletion(empty).
|
||||
return NormalCompletion(undefined);
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
import { NormalCompletion } from '../completion.mts';
|
||||
import type { ParseNode } from '../parser/ParseNode.mts';
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-statement-semantics-runtime-semantics-evaluation */
|
||||
// HoistableDeclaration :
|
||||
// GeneratorDeclaration
|
||||
// AsyncFunctionDeclaration
|
||||
// AsyncGeneratorDeclaration
|
||||
export function Evaluate_HoistableDeclaration(_HoistableDeclaration: ParseNode.HoistableDeclaration) {
|
||||
// 1. Return NormalCompletion(empty).
|
||||
return NormalCompletion(undefined);
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
import { StringValue } from '../static-semantics/all.mts';
|
||||
import type { ParseNode } from '../parser/ParseNode.mts';
|
||||
import type { ReferenceRecord } from '../value.mts';
|
||||
import type { PlainEvaluator } from '../evaluator.mts';
|
||||
import { ResolveBinding } from '#self';
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-identifiers-runtime-semantics-evaluation */
|
||||
// IdentifierReference :
|
||||
// Identifier
|
||||
// `yield`
|
||||
// `await`
|
||||
export function* Evaluate_IdentifierReference(IdentifierReference: ParseNode.IdentifierReference): PlainEvaluator<ReferenceRecord> {
|
||||
// 1. Return ? ResolveBinding(StringValue of Identifier).
|
||||
return yield* ResolveBinding(StringValue(IdentifierReference), undefined, IdentifierReference.strict);
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
import { Evaluate } from '../evaluator.mts';
|
||||
import {
|
||||
Completion,
|
||||
EnsureCompletion,
|
||||
NormalCompletion,
|
||||
Q,
|
||||
UpdateEmpty,
|
||||
} from '../completion.mts';
|
||||
import { Value } from '../value.mts';
|
||||
import type { ParseNode } from '../parser/ParseNode.mts';
|
||||
import {
|
||||
GetValue,
|
||||
ToBoolean,
|
||||
} from '#self';
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-if-statement-runtime-semantics-evaluation */
|
||||
// IfStatement :
|
||||
// `if` `(` Expression `)` Statement `else` Statement
|
||||
// `if` `(` Expression `)` Statement
|
||||
export function* Evaluate_IfStatement({ Expression, Statement_a, Statement_b }: ParseNode.IfStatement) {
|
||||
// 1. Let exprRef be the result of evaluating Expression.
|
||||
const exprRef = Q(yield* Evaluate(Expression));
|
||||
// 2. Let exprValue be ! ToBoolean(? GetValue(exprRef)).
|
||||
const exprValue = ToBoolean(Q(yield* GetValue(exprRef)));
|
||||
if (Statement_b) {
|
||||
let stmtCompletion;
|
||||
// 3. If exprValue is true, then
|
||||
if (exprValue === Value.true) {
|
||||
// a. Let stmtCompletion be the result of evaluating the first Statement.
|
||||
stmtCompletion = yield* Evaluate(Statement_a);
|
||||
} else { // 4. Else,
|
||||
// a. Let stmtCompletion be the result of evaluating the second Statement.
|
||||
stmtCompletion = yield* Evaluate(Statement_b);
|
||||
}
|
||||
// 5. Return Completion(UpdateEmpty(stmtCompletion, undefined)).
|
||||
return Completion(UpdateEmpty(EnsureCompletion(stmtCompletion), Value.undefined));
|
||||
} else {
|
||||
// 3. If exprValue is false, then
|
||||
if (exprValue === Value.false) {
|
||||
// a. Return NormalCompletion(undefined).
|
||||
return NormalCompletion(Value.undefined);
|
||||
} else { // 4. Else,
|
||||
// a. Let stmtCompletion be the result of evaluating Statement.
|
||||
const stmtCompletion = yield* Evaluate(Statement_a);
|
||||
// b. Return Completion(UpdateEmpty(stmtCompletion, undefined)).
|
||||
return Completion(UpdateEmpty(EnsureCompletion(stmtCompletion), Value.undefined));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,134 @@
|
||||
import { surroundingAgent, HostLoadImportedModule } from '../host-defined/engine.mts';
|
||||
import { Evaluate, type ValueEvaluator } from '../evaluator.mts';
|
||||
import {
|
||||
Q, X, IfAbruptRejectPromise,
|
||||
} from '../completion.mts';
|
||||
import {
|
||||
AbstractModuleRecord, AllImportAttributesSupported, Call, CyclicModuleRecord, EnumerableOwnProperties, Get, JSStringValue, NullValue, ObjectValue, Realm, Value, type ModuleRequestRecord, type PromiseObject, type ScriptRecord,
|
||||
} from '../index.mts';
|
||||
import type { ParseNode } from '../parser/ParseNode.mts';
|
||||
import { __ts_cast__ } from '../helpers.mts';
|
||||
import {
|
||||
GetValue,
|
||||
ToString,
|
||||
NewPromiseCapability,
|
||||
GetActiveScriptOrModule,
|
||||
} from '#self';
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-import-calls */
|
||||
// ImportCall : `import` `(` AssignmentExpression `)`
|
||||
export function* Evaluate_ImportCall(ImportCall: ParseNode.ImportCall): ValueEvaluator<PromiseObject> {
|
||||
Q(surroundingAgent.debugger_cannotPreview);
|
||||
return yield* EvaluateImportCall(ImportCall.AssignmentExpression, ImportCall.OptionsExpression, ImportCall.Phase);
|
||||
}
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-evaluate-import-call */
|
||||
function* EvaluateImportCall(
|
||||
specifiersExpression: ParseNode.AssignmentExpressionOrHigher,
|
||||
optionsExpression: undefined | ParseNode.AssignmentExpressionOrHigher,
|
||||
phase: 'defer' | 'evaluation',
|
||||
): ValueEvaluator<PromiseObject> {
|
||||
// 1. Let referrer be ! GetActiveScriptOrModule().
|
||||
let referrer: NullValue | AbstractModuleRecord | ScriptRecord | Realm = X(GetActiveScriptOrModule());
|
||||
// 2. If referrer is null, set referrer to the current Realm Record.
|
||||
if (referrer instanceof NullValue) {
|
||||
referrer = surroundingAgent.currentRealmRecord;
|
||||
}
|
||||
// 3. Let specifierRef be ? Evaluation of AssignmentExpression.
|
||||
const specifierRef = Q(yield* Evaluate(specifiersExpression));
|
||||
// 4. Let specifier be ? GetValue(specifierRef).
|
||||
const specifier = Q(yield* GetValue(specifierRef));
|
||||
let options: Value;
|
||||
// 5. If optionsExpression is present, then
|
||||
if (optionsExpression) {
|
||||
// a. Let optionsRef be ? Evaluation of optionsExpression.
|
||||
const optionsRef = Q(yield* Evaluate(optionsExpression));
|
||||
// b. Let options be ? GetValue(optionsRef).
|
||||
options = Q(yield* GetValue(optionsRef));
|
||||
} else { // 6. Else,
|
||||
// a. Let options be undefined.
|
||||
options = Value.undefined;
|
||||
}
|
||||
// 7. Let promiseCapability be ! NewPromiseCapability(%Promise%).
|
||||
const promiseCapability = X(NewPromiseCapability(surroundingAgent.intrinsic('%Promise%')));
|
||||
// 8. Let specifierString be ToString(specifier).
|
||||
const specifierString = yield* ToString(specifier);
|
||||
// 9. IfAbruptRejectPromise(specifierString, promiseCapability).
|
||||
IfAbruptRejectPromise(specifierString, promiseCapability);
|
||||
__ts_cast__<JSStringValue>(specifierString);
|
||||
// 10. Let attributes nw a new empty List.
|
||||
const attributes = [];
|
||||
// 11. If options is not undefined, then
|
||||
if (options !== Value.undefined) {
|
||||
// a. If options is not an Object, then
|
||||
if (!(options instanceof ObjectValue)) {
|
||||
// i. Perform ! Call(promiseCapability.[[Reject]], undefined, « a newly created TypeError object »).
|
||||
X(Call(promiseCapability.Reject, Value.undefined, [
|
||||
surroundingAgent.Throw('TypeError', 'NotAnObject', options).Value,
|
||||
]));
|
||||
// ii. Return promiseCapability.[[Promise]].
|
||||
return promiseCapability.Promise;
|
||||
}
|
||||
// b. Let attributesObj be Completion(Get(options, "with")).
|
||||
const attributesObj = yield* Get(options, Value('with'));
|
||||
// c. IfAbruptRejectPromise(attributesObj, promiseCapability).
|
||||
IfAbruptRejectPromise(attributesObj, promiseCapability);
|
||||
__ts_cast__<Value>(attributesObj);
|
||||
// d. If attributesObj is not undefined, then
|
||||
if (attributesObj !== Value.undefined) {
|
||||
// i. If attributesObj is not an Object, then
|
||||
if (!(attributesObj instanceof ObjectValue)) {
|
||||
// 1. Perform ! Call(promiseCapability.[[Reject]], undefined, « a newly created TypeError object »).
|
||||
X(Call(promiseCapability.Reject, Value.undefined, [
|
||||
surroundingAgent.Throw('TypeError', 'NotAnObject', attributesObj).Value,
|
||||
]));
|
||||
// 2. Return promiseCapability.[[Promise]].
|
||||
return promiseCapability.Promise;
|
||||
}
|
||||
// ii. Let entries be Completion(EnumerableOwnProperties(attributesObj, key+value)).
|
||||
const entries = yield* EnumerableOwnProperties(attributesObj, 'key+value');
|
||||
// iii. IfAbruptRejectPromise(entries, promiseCapability).
|
||||
IfAbruptRejectPromise(entries, promiseCapability);
|
||||
__ts_cast__<ObjectValue[]>(entries);
|
||||
// iv. For each element entry of entries, do
|
||||
for (const entry of entries) {
|
||||
// 1. Let key be ! Get(entry, "0").
|
||||
const key = Q(yield* Get(entry, Value('0')));
|
||||
// 2. Let value be ! Get(entry, "1").
|
||||
const value = Q(yield* Get(entry, Value('1')));
|
||||
// 3. If key is a String, then
|
||||
if (key instanceof JSStringValue) {
|
||||
// a. If value is not a String, then
|
||||
if (!(value instanceof JSStringValue)) {
|
||||
// i. Perform ! Call(promiseCapability.[[Reject]], undefined, « a newly created TypeError object »).
|
||||
X(Call(promiseCapability.Reject, Value.undefined, [
|
||||
surroundingAgent.Throw('TypeError', 'NotAString', value).Value,
|
||||
]));
|
||||
// ii. Return promiseCapability.[[Promise]].
|
||||
return promiseCapability.Promise;
|
||||
}
|
||||
// b. Append the ImportAttribute Record { [[Key]]: key, [[Value]]: value } to attributes.
|
||||
attributes.push({ Key: key, Value: value });
|
||||
}
|
||||
}
|
||||
// e. If AllImportAttributesSupported(attributes) is false, then
|
||||
const unsupportedAttributeKey = AllImportAttributesSupported(attributes);
|
||||
if (unsupportedAttributeKey) {
|
||||
// i. Perform ! Call(promiseCapability.[[Reject]], undefined, « a newly created TypeError object »).
|
||||
X(Call(promiseCapability.Reject, Value.undefined, [
|
||||
surroundingAgent.Throw('TypeError', 'UnsupportedImportAttribute', unsupportedAttributeKey).Value,
|
||||
]));
|
||||
// ii. Return promiseCapability.[[Promise]].
|
||||
return promiseCapability.Promise;
|
||||
}
|
||||
// f. Sort attributes according to the lexicographic order of their [[Key]] field, treating the value of each such field as a sequence of UTF-16 code unit values.
|
||||
attributes.sort((a, b) => (a.Key.value < b.Key.value ? -1 : 1));
|
||||
}
|
||||
}
|
||||
// 12. Let moduleRequest be a new ModuleRequest Record { [[Specifier]]: specifierString, [[Attributes]]: attributes }.
|
||||
const moduleRequest: ModuleRequestRecord = { Specifier: specifierString, Attributes: attributes, Phase: phase };
|
||||
// 10. Perform HostLoadImportedModule(referrer, specifierString, ~empty~, promiseCapability).
|
||||
HostLoadImportedModule(referrer as CyclicModuleRecord | ScriptRecord | Realm, moduleRequest, undefined, promiseCapability);
|
||||
// 9. Return promiseCapability.[[Promise]].
|
||||
return promiseCapability.Promise;
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
import { NormalCompletion } from '../completion.mts';
|
||||
import type { ParseNode } from '../parser/ParseNode.mts';
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-module-semantics-runtime-semantics-evaluation */
|
||||
// ModuleItem : ImportDeclaration
|
||||
export function Evaluate_ImportDeclaration(_ImportDeclaration: ParseNode.ImportDeclaration) {
|
||||
// 1. Return NormalCompletion(empty).
|
||||
return NormalCompletion(undefined);
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
import { HostGetImportMetaProperties, HostFinalizeImportMeta } from '../host-defined/engine.mts';
|
||||
import { ObjectValue, Value } from '../value.mts';
|
||||
import { X } from '../completion.mts';
|
||||
import { SourceTextModuleRecord } from '../modules.mts';
|
||||
import type { ParseNode } from '../parser/ParseNode.mts';
|
||||
import {
|
||||
Assert,
|
||||
GetActiveScriptOrModule,
|
||||
OrdinaryObjectCreate,
|
||||
CreateDataPropertyOrThrow,
|
||||
} from '#self';
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-meta-properties */
|
||||
// ImportMeta : `import` `.` `meta`
|
||||
export function Evaluate_ImportMeta(_ImportMeta: ParseNode.ImportMeta) {
|
||||
// 1. Let module be ! GetActiveScriptOrModule().
|
||||
const module = X(GetActiveScriptOrModule());
|
||||
// 2. Assert: module is a Source Text Module Record.
|
||||
Assert(module instanceof SourceTextModuleRecord);
|
||||
// 3. Let importMeta be module.[[ImportMeta]].
|
||||
let importMeta = module.ImportMeta;
|
||||
// 4. If importMeta is empty, then
|
||||
if (importMeta === undefined) {
|
||||
// a. Set importMeta to ! OrdinaryObjectCreate(null).
|
||||
importMeta = X(OrdinaryObjectCreate(Value.null));
|
||||
// b. Let importMetaValues be ! HostGetImportMetaProperties(module).
|
||||
const importMetaValues = X(HostGetImportMetaProperties(module));
|
||||
// c. For each Record { [[Key]], [[Value]] } p that is an element of importMetaValues, do
|
||||
for (const p of importMetaValues) {
|
||||
// i. Perform ! CreateDataPropertyOrThrow(importMeta, p.[[Key]], p.[[Value]]).
|
||||
X(CreateDataPropertyOrThrow(importMeta, p.Key, p.Value));
|
||||
}
|
||||
// d. Perform ! HostFinalizeImportMeta(importMeta, module).
|
||||
X(HostFinalizeImportMeta(importMeta, module));
|
||||
// e. Set module.[[ImportMeta]] to importMeta.
|
||||
module.ImportMeta = importMeta;
|
||||
// f. Return importMeta.
|
||||
return importMeta;
|
||||
} else { // 5. Else,
|
||||
// a. Assert: Type(importMeta) is Object.
|
||||
Assert(importMeta instanceof ObjectValue);
|
||||
// b. Return importMeta.
|
||||
return importMeta;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
import { surroundingAgent } from '../host-defined/engine.mts';
|
||||
import { Value } from '../value.mts';
|
||||
import type { ParseNode } from '../parser/ParseNode.mts';
|
||||
import { OrdinaryFunctionCreate, SetFunctionName, sourceTextMatchedBy } from '#self';
|
||||
import type { PrivateName, PropertyKeyValue } from '#self';
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-runtime-semantics-instantiatearrowfunctionexpression */
|
||||
// ArrowFunction : ArrowParameters `=>` ConciseBody
|
||||
export function InstantiateArrowFunctionExpression(ArrowFunction: ParseNode.ArrowFunction, name?: PropertyKeyValue | PrivateName) {
|
||||
const { ArrowParameters, ConciseBody } = ArrowFunction;
|
||||
// 1. If name is not present, set name to "".
|
||||
if (name === undefined) {
|
||||
name = Value('');
|
||||
}
|
||||
// 2. Let scope be the LexicalEnvironment of the running execution context.
|
||||
const scope = surroundingAgent.runningExecutionContext.LexicalEnvironment;
|
||||
// 3. Let privateScope be the running execution context's PrivateEnvironment.
|
||||
const privateScope = surroundingAgent.runningExecutionContext.PrivateEnvironment;
|
||||
// 4. Let sourceText be the source text matched by ArrowFunction.
|
||||
const sourceText = sourceTextMatchedBy(ArrowFunction);
|
||||
// 5. Let closure be OrdinaryFunctionCreate(%Function.prototype%, sourceText, ArrowParameters, ConciseBody, lexical-this, scope, privateScope).
|
||||
const closure = OrdinaryFunctionCreate(
|
||||
surroundingAgent.intrinsic('%Function.prototype%'),
|
||||
sourceText,
|
||||
ArrowParameters,
|
||||
ConciseBody,
|
||||
'lexical-this',
|
||||
scope,
|
||||
privateScope,
|
||||
);
|
||||
// 6. Perform SetFunctionName(closure, name).
|
||||
SetFunctionName(closure, name);
|
||||
// 7. Return closure.
|
||||
return closure;
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
import { surroundingAgent } from '../host-defined/engine.mts';
|
||||
import { Value } from '../value.mts';
|
||||
import type { ParseNode } from '../parser/ParseNode.mts';
|
||||
import { OrdinaryFunctionCreate, SetFunctionName, sourceTextMatchedBy } from '#self';
|
||||
import type { PrivateName, PropertyKeyValue } from '#self';
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-runtime-semantics-instantiateasyncarrowfunctionexpression */
|
||||
// AsyncArrowFunction : ArrowParameters `=>` AsyncConciseBody
|
||||
export function InstantiateAsyncArrowFunctionExpression(AsyncArrowFunction: ParseNode.AsyncArrowFunction, name?: PropertyKeyValue | PrivateName) {
|
||||
const { ArrowParameters, AsyncConciseBody } = AsyncArrowFunction;
|
||||
// 1. If name is not present, set name to "".
|
||||
if (name === undefined) {
|
||||
name = Value('');
|
||||
}
|
||||
// 2. Let scope be the LexicalEnvironment of the running execution context.
|
||||
const scope = surroundingAgent.runningExecutionContext.LexicalEnvironment;
|
||||
// 3. Let privateScope be the running execution context's PrivateEnvironment.
|
||||
const privateScope = surroundingAgent.runningExecutionContext.PrivateEnvironment;
|
||||
// 4. Let sourceText be the source text matched by AsyncArrowFunction.
|
||||
const sourceText = sourceTextMatchedBy(AsyncArrowFunction);
|
||||
// 5. Let parameters be AsyncArrowBindingIdentifier.
|
||||
const parameters = ArrowParameters;
|
||||
// 6. Let closure be OrdinaryFunctionCreate(%AsyncFunction.prototype%, sourceText, ArrowParameters, AsyncConciseBody, lexical-this, scope, privateScope).
|
||||
const closure = OrdinaryFunctionCreate(
|
||||
surroundingAgent.intrinsic('%AsyncFunction.prototype%'),
|
||||
sourceText,
|
||||
parameters,
|
||||
AsyncConciseBody,
|
||||
'lexical-this',
|
||||
scope,
|
||||
privateScope,
|
||||
);
|
||||
// 7. Perform SetFunctionName(closure, name).
|
||||
SetFunctionName(closure, name);
|
||||
// 8. Return closure.
|
||||
return closure;
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
import { surroundingAgent } from '../host-defined/engine.mts';
|
||||
import {
|
||||
PrivateName, Value, type PropertyKeyValue,
|
||||
} from '../value.mts';
|
||||
import { StringValue } from '../static-semantics/all.mts';
|
||||
import { X } from '../completion.mts';
|
||||
import type { ParseNode } from '../parser/ParseNode.mts';
|
||||
import {
|
||||
Assert,
|
||||
OrdinaryFunctionCreate,
|
||||
SetFunctionName,
|
||||
sourceTextMatchedBy,
|
||||
DeclarativeEnvironmentRecord,
|
||||
} from '#self';
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-runtime-semantics-instantiateasyncfunctionexpression */
|
||||
export function InstantiateAsyncFunctionExpression(AsyncFunctionExpression: ParseNode.AsyncFunctionExpression, name?: PropertyKeyValue | PrivateName) {
|
||||
const { BindingIdentifier, FormalParameters, AsyncBody } = AsyncFunctionExpression;
|
||||
if (BindingIdentifier) {
|
||||
// 1. Assert: name is not present.
|
||||
Assert(name === undefined);
|
||||
// 2. Set name to StringValue of BindingIdentifier.
|
||||
name = StringValue(BindingIdentifier);
|
||||
// 3. Let scope be the LexicalEnvironment of the running execution context.
|
||||
const scope = surroundingAgent.runningExecutionContext.LexicalEnvironment;
|
||||
// 4. Let funcEnv be ! NewDeclarativeEnvironment(scope).
|
||||
const funcEnv = X(new DeclarativeEnvironmentRecord(scope));
|
||||
// 5. Perform ! funcEnv.CreateImmutableBinding(name, false).
|
||||
X(funcEnv.CreateImmutableBinding(name, Value.false));
|
||||
// 6. Let privateScope be the running execution context's PrivateEnvironment.
|
||||
const privateScope = surroundingAgent.runningExecutionContext.PrivateEnvironment;
|
||||
// 7. Let sourceText be the source text matched by AsyncFunctionExpression.
|
||||
const sourceText = sourceTextMatchedBy(AsyncFunctionExpression);
|
||||
// 8. Let closure be ! OrdinaryFunctionCreate(%AsyncFunction.prototype%, sourceText, FormalParameters, AsyncBody, non-lexical-this, funcEnv, privateScope).
|
||||
const closure = X(OrdinaryFunctionCreate(
|
||||
surroundingAgent.intrinsic('%AsyncFunction.prototype%'),
|
||||
sourceText,
|
||||
FormalParameters,
|
||||
AsyncBody,
|
||||
'non-lexical-this',
|
||||
funcEnv,
|
||||
privateScope,
|
||||
));
|
||||
// 9. Perform ! SetFunctionName(closure, name).
|
||||
X(SetFunctionName(closure, name));
|
||||
// 10. Perform ! funcEnv.InitializeBinding(name, closure).
|
||||
X(funcEnv.InitializeBinding(name, closure));
|
||||
// 11. Return closure.
|
||||
return closure;
|
||||
}
|
||||
// 1. If name is not present, set name to "".
|
||||
if (name === undefined) {
|
||||
name = Value('');
|
||||
}
|
||||
// 2. Let scope be the LexicalEnvironment of the running execution context.
|
||||
const scope = surroundingAgent.runningExecutionContext.LexicalEnvironment;
|
||||
// 3. Let privateScope be the running execution context's PrivateEnvironment.
|
||||
const privateScope = surroundingAgent.runningExecutionContext.PrivateEnvironment;
|
||||
// 4. Let sourceText be the source text matched by AsyncFunctionExpression.
|
||||
const sourceText = sourceTextMatchedBy(AsyncFunctionExpression);
|
||||
// 5. Let closure be ! OrdinaryFunctionCreate(%AsyncFunction.prototype%, sourceText, FormalParameters, AsyncBody, non-lexical-this, scope, privateScope).
|
||||
const closure = X(OrdinaryFunctionCreate(
|
||||
surroundingAgent.intrinsic('%AsyncFunction.prototype%'),
|
||||
sourceText,
|
||||
FormalParameters,
|
||||
AsyncBody,
|
||||
'non-lexical-this',
|
||||
scope,
|
||||
privateScope,
|
||||
));
|
||||
// 6. Perform SetFunctionName(closure, name).
|
||||
SetFunctionName(closure, name);
|
||||
// 7. Return closure.
|
||||
return closure;
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
import { surroundingAgent } from '../host-defined/engine.mts';
|
||||
import {
|
||||
Value, Descriptor, type PropertyKeyValue, PrivateName,
|
||||
} from '../value.mts';
|
||||
import { StringValue } from '../static-semantics/all.mts';
|
||||
import { X } from '../completion.mts';
|
||||
import type { ParseNode } from '../parser/ParseNode.mts';
|
||||
import {
|
||||
Assert,
|
||||
DefinePropertyOrThrow,
|
||||
OrdinaryFunctionCreate,
|
||||
OrdinaryObjectCreate,
|
||||
SetFunctionName,
|
||||
sourceTextMatchedBy,
|
||||
DeclarativeEnvironmentRecord,
|
||||
} from '#self';
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-runtime-semantics-instantiateasyncgeneratorfunctionexpression */
|
||||
// AsyncGeneratorExpression :
|
||||
// `async` `function` `*` `(` FormalParameters `)` `{` AsyncGeneratorBody `}`
|
||||
// `async` `function` `*` BindingIdentifier `(` FormalParameters `)` `{` AsyncGeneratorBody `}`
|
||||
export function InstantiateAsyncGeneratorFunctionExpression(AsyncGeneratorExpression: ParseNode.AsyncGeneratorExpression, name?: PropertyKeyValue | PrivateName) {
|
||||
const { BindingIdentifier, FormalParameters, AsyncGeneratorBody } = AsyncGeneratorExpression;
|
||||
if (BindingIdentifier) {
|
||||
// 1. Assert: name is not present.
|
||||
Assert(name === undefined);
|
||||
// 2. Set name to StringValue of BindingIdentifier.
|
||||
name = StringValue(BindingIdentifier);
|
||||
// 3. Let scope be the running execution context's LexicalEnvironment.
|
||||
const scope = surroundingAgent.runningExecutionContext.LexicalEnvironment;
|
||||
// 4. Let funcEnv be NewDeclarativeEnvironment(scope).
|
||||
const funcEnv = new DeclarativeEnvironmentRecord(scope);
|
||||
// 5. Perform funcEnv.CreateImmutableBinding(name, false).
|
||||
funcEnv.CreateImmutableBinding(name, Value.false);
|
||||
// 6. Let privateScope be the running execution context's PrivateEnvironment.
|
||||
const privateScope = surroundingAgent.runningExecutionContext.PrivateEnvironment;
|
||||
// 7. Let source text be the source textmatched by AsyncGeneratorExpression.
|
||||
const sourceText = sourceTextMatchedBy(AsyncGeneratorExpression);
|
||||
// 8. Let closure be OrdinaryFunctionCreate(%AsyncGeneratorFunction.prototype%, sourceText, FormalParameters, AsyncGeneratorBody, non-lexical-this, funcEnv, privateScope).
|
||||
const closure = X(OrdinaryFunctionCreate(surroundingAgent.intrinsic('%AsyncGeneratorFunction.prototype%'), sourceText, FormalParameters, AsyncGeneratorBody, 'non-lexical-this', funcEnv, privateScope));
|
||||
// 9. Perform SetFunctionName(closure, name).
|
||||
SetFunctionName(closure, name);
|
||||
// 10. Let prototype be OrdinaryObjectCreate(%AsyncGeneratorFunction.prototype.prototype%).
|
||||
const prototype = OrdinaryObjectCreate(surroundingAgent.intrinsic('%AsyncGeneratorFunction.prototype.prototype%'));
|
||||
// 11. Perform DefinePropertyOrThrow(closure, "prototype", PropertyDescriptor { [[Value]]: prototype, [[Writable]]: true, [[Enumerable]]: false, [[Configurable]]: false }).
|
||||
X(DefinePropertyOrThrow(
|
||||
closure,
|
||||
Value('prototype'),
|
||||
Descriptor({
|
||||
Value: prototype,
|
||||
Writable: Value.true,
|
||||
Enumerable: Value.false,
|
||||
Configurable: Value.false,
|
||||
}),
|
||||
));
|
||||
// 12. Perform funcEnv.InitializeBinding(name, closure).
|
||||
X(funcEnv.InitializeBinding(name, closure));
|
||||
// 13. Return closure.
|
||||
return closure;
|
||||
}
|
||||
// 1. If name is not present, set name to "".
|
||||
if (name === undefined) {
|
||||
name = Value('');
|
||||
}
|
||||
// 2. Let scope be the LexicalEnvironment of the running execution context.
|
||||
const scope = surroundingAgent.runningExecutionContext.LexicalEnvironment;
|
||||
// 3. Let privateScope be the running execution context's PrivateEnvironment.
|
||||
const privateScope = surroundingAgent.runningExecutionContext.PrivateEnvironment;
|
||||
// 4. Let sourceText be the source text matched by AsyncGeneratorExpression.
|
||||
const sourceText = sourceTextMatchedBy(AsyncGeneratorExpression);
|
||||
// 5. Let closure be ! OrdinaryFunctionCreate(%AsyncGeneratorFunction.prototype%, sourceText, FormalParameters, AsyncGeneratorBody, non-lexical-this, scope, privateScope).
|
||||
const closure = X(OrdinaryFunctionCreate(surroundingAgent.intrinsic('%AsyncGeneratorFunction.prototype%'), sourceText, FormalParameters, AsyncGeneratorBody, 'non-lexical-this', scope, privateScope));
|
||||
// 6. Perform SetFunctionName(closure, name).
|
||||
SetFunctionName(closure, name);
|
||||
// 7. Let prototype be ! OrdinaryObjectCreate(%AsyncGeneratorFunction.prototype.prototype%).
|
||||
const prototype = OrdinaryObjectCreate(surroundingAgent.intrinsic('%AsyncGeneratorFunction.prototype.prototype%'));
|
||||
// 8. Perform ! DefinePropertyOrThrow(closure, "prototype", PropertyDescriptor { [[Value]]: prototype, [[Writable]]: true, [[Enumerable]]: false, [[Configurable]]: false }).
|
||||
X(DefinePropertyOrThrow(
|
||||
closure,
|
||||
Value('prototype'),
|
||||
Descriptor({
|
||||
Value: prototype,
|
||||
Writable: Value.true,
|
||||
Enumerable: Value.false,
|
||||
Configurable: Value.false,
|
||||
}),
|
||||
));
|
||||
// 9. Return closure.
|
||||
return closure;
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
import { X } from '../completion.mts';
|
||||
import { surroundingAgent } from '../host-defined/engine.mts';
|
||||
import { OutOfRange } from '../helpers.mts';
|
||||
import { Descriptor, Value } from '../value.mts';
|
||||
import { StringValue } from '../static-semantics/all.mts';
|
||||
import type { ParseNode } from '../parser/ParseNode.mts';
|
||||
import {
|
||||
DefinePropertyOrThrow,
|
||||
MakeConstructor,
|
||||
OrdinaryObjectCreate,
|
||||
SetFunctionName,
|
||||
OrdinaryFunctionCreate,
|
||||
sourceTextMatchedBy,
|
||||
} from '#self';
|
||||
import type { EnvironmentRecord, NullValue, PrivateEnvironmentRecord } from '#self';
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-function-definitions-runtime-semantics-instantiatefunctionobject */
|
||||
// FunctionDeclaration :
|
||||
// `function` BindingIdentifier `(` FormalParameters `)` `{` FunctionBody `}`
|
||||
// `function` `(` FormalParameters `)` `{` FunctionBody `}`
|
||||
export function InstantiateFunctionObject_FunctionDeclaration(FunctionDeclaration: ParseNode.FunctionDeclaration, env: EnvironmentRecord, privateEnv: PrivateEnvironmentRecord | NullValue) {
|
||||
const { BindingIdentifier, FormalParameters, FunctionBody } = FunctionDeclaration;
|
||||
// 1. Let name be StringValue of BindingIdentifier.
|
||||
const name = BindingIdentifier ? StringValue(BindingIdentifier) : Value('default');
|
||||
// 2. Let sourceText be the source text matched by FunctionDeclaration.
|
||||
const sourceText = sourceTextMatchedBy(FunctionDeclaration);
|
||||
// 3. Let F be OrdinaryFunctionCreate(%Function.prototype%, sourceText, FormalParameters, FunctionBody, non-lexical-this, scope, privateScope).
|
||||
const F = X(OrdinaryFunctionCreate(surroundingAgent.intrinsic('%Function.prototype%'), sourceText, FormalParameters, FunctionBody, 'non-lexical-this', env, privateEnv));
|
||||
// 4. Perform SetFunctionName(F, name).
|
||||
SetFunctionName(F, name);
|
||||
// 5. Perform MakeConstructor(F).
|
||||
MakeConstructor(F);
|
||||
// 6. Return F.
|
||||
return F;
|
||||
}
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-generator-function-definitions-runtime-semantics-instantiatefunctionobject */
|
||||
// GeneratorDeclaration :
|
||||
// `function` `*` BindingIdentifier `(` FormalParameters `)` `{` GeneratorBody `}`
|
||||
// `function` `*` `(` FormalParameters `)` `{` GeneratorBody `}`
|
||||
export function InstantiateFunctionObject_GeneratorDeclaration(GeneratorDeclaration: ParseNode.GeneratorDeclaration, env: EnvironmentRecord, privateEnv: PrivateEnvironmentRecord | NullValue) {
|
||||
const { BindingIdentifier, FormalParameters, GeneratorBody } = GeneratorDeclaration;
|
||||
// 1. Let name be StringValue of BindingIdentifier.
|
||||
const name = BindingIdentifier ? StringValue(BindingIdentifier) : Value('default');
|
||||
// 2. Let sourceText be the source text matched by GeneratorDeclaration.
|
||||
const sourceText = sourceTextMatchedBy(GeneratorDeclaration);
|
||||
// 3. Let F be OrdinaryFunctionCreate(%GeneratorFunction.prototype%, sourceText, FormalParameters, GeneratorBody, non-lexical-this, scope, privateScope).
|
||||
const F = X(OrdinaryFunctionCreate(surroundingAgent.intrinsic('%GeneratorFunction.prototype%'), sourceText, FormalParameters, GeneratorBody, 'non-lexical-this', env, privateEnv));
|
||||
// 4. Perform SetFunctionName(F, name).
|
||||
SetFunctionName(F, name);
|
||||
// 5. Let prototype be OrdinaryObjectCreate(%GeneratorFunction.prototype.prototype%).
|
||||
const prototype = X(OrdinaryObjectCreate(surroundingAgent.intrinsic('%GeneratorFunction.prototype.prototype%')));
|
||||
// 6. Perform DefinePropertyOrThrow(F, "prototype", PropertyDescriptor { [[Value]]: prototype, [[Writable]]: true, [[Enumerable]]: false, [[Configurable]]: false }).
|
||||
X(DefinePropertyOrThrow(F, Value('prototype'), Descriptor({
|
||||
Value: prototype,
|
||||
Writable: Value.true,
|
||||
Enumerable: Value.false,
|
||||
Configurable: Value.false,
|
||||
})));
|
||||
// 7. Return F.
|
||||
return F;
|
||||
}
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-async-function-definitions-InstantiateFunctionObject */
|
||||
// AsyncFunctionDeclaration :
|
||||
// `async` `function` BindingIdentifier `(` FormalParameters `)` `{` AsyncBody `}`
|
||||
// `async` `function` `(` FormalParameters `)` `{` AsyncBody `}`
|
||||
export function InstantiateFunctionObject_AsyncFunctionDeclaration(AsyncFunctionDeclaration: ParseNode.AsyncFunctionDeclaration, env: EnvironmentRecord, privateEnv: PrivateEnvironmentRecord | NullValue) {
|
||||
const { BindingIdentifier, FormalParameters, AsyncBody } = AsyncFunctionDeclaration;
|
||||
// 1. Let name be StringValue of BindingIdentifier.
|
||||
const name = BindingIdentifier ? StringValue(BindingIdentifier) : Value('default');
|
||||
// 2. Let sourceText be the source text matched by AsyncFunctionDeclaration.
|
||||
const sourceText = sourceTextMatchedBy(AsyncFunctionDeclaration);
|
||||
// 3. Let F be ! OrdinaryFunctionCreate(%AsyncFunction.prototype%, sourceText, FormalParameters, AsyncBody, non-lexical-this, scope, privateScope).
|
||||
const F = X(OrdinaryFunctionCreate(surroundingAgent.intrinsic('%AsyncFunction.prototype%'), sourceText, FormalParameters, AsyncBody, 'non-lexical-this', env, privateEnv));
|
||||
// 4. Perform ! SetFunctionName(F, name).
|
||||
SetFunctionName(F, name);
|
||||
// 5. Return F.
|
||||
return F;
|
||||
}
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-asyncgenerator-definitions-evaluatebody */
|
||||
// AsyncGeneratorDeclaration :
|
||||
// `async` `function` `*` BindingIdentifier `(` FormalParameters`)` `{` AsyncGeneratorBody `}`
|
||||
// `async` `function` `*` `(` FormalParameters`)` `{` AsyncGeneratorBody `}`
|
||||
export function InstantiateFunctionObject_AsyncGeneratorDeclaration(AsyncGeneratorDeclaration: ParseNode.AsyncGeneratorDeclaration, env: EnvironmentRecord, privateEnv: PrivateEnvironmentRecord | NullValue) {
|
||||
const { BindingIdentifier, FormalParameters, AsyncGeneratorBody } = AsyncGeneratorDeclaration;
|
||||
// 1. Let name be StringValue of BindingIdentifier.
|
||||
const name = BindingIdentifier ? StringValue(BindingIdentifier) : Value('default');
|
||||
// 2. Let sourceText be the source text matched by AsyncGeneratorDeclaration.
|
||||
const sourceText = sourceTextMatchedBy(AsyncGeneratorDeclaration);
|
||||
// 3. Let F be ! OrdinaryFunctionCreate(%AsyncGeneratorFunction.prototype%, sourceText, FormalParameters, AsyncGeneratorBody, non-lexical-this, scope, privateScope).
|
||||
const F = X(OrdinaryFunctionCreate(surroundingAgent.intrinsic('%AsyncGeneratorFunction.prototype%'), sourceText, FormalParameters, AsyncGeneratorBody, 'non-lexical-this', env, privateEnv));
|
||||
// 4. Perform ! SetFunctionName(F, name).
|
||||
SetFunctionName(F, name);
|
||||
// 5. Let prototype be ! OrdinaryObjectCreate(%AsyncGeneratorFunction.prototype.prototype%).
|
||||
const prototype = X(OrdinaryObjectCreate(surroundingAgent.intrinsic('%AsyncGeneratorFunction.prototype.prototype%')));
|
||||
// 6. Perform ! DefinePropertyOrThrow(F, "prototype", PropertyDescriptor { [[Value]]: prototype, [[Writable]]: true, [[Enumerable]]: false, [[Configurable]]: false }).
|
||||
X(DefinePropertyOrThrow(F, Value('prototype'), Descriptor({
|
||||
Value: prototype,
|
||||
Writable: Value.true,
|
||||
Enumerable: Value.false,
|
||||
Configurable: Value.false,
|
||||
})));
|
||||
// 7. Return F.
|
||||
return F;
|
||||
}
|
||||
|
||||
export function InstantiateFunctionObject(AnyFunctionDeclaration: ParseNode.FunctionDeclaration | ParseNode.GeneratorDeclaration | ParseNode.AsyncFunctionDeclaration | ParseNode.AsyncGeneratorDeclaration, env: EnvironmentRecord, privateEnv: PrivateEnvironmentRecord | NullValue) {
|
||||
switch (AnyFunctionDeclaration.type) {
|
||||
case 'FunctionDeclaration':
|
||||
return InstantiateFunctionObject_FunctionDeclaration(AnyFunctionDeclaration, env, privateEnv);
|
||||
case 'GeneratorDeclaration':
|
||||
return InstantiateFunctionObject_GeneratorDeclaration(AnyFunctionDeclaration, env, privateEnv);
|
||||
case 'AsyncFunctionDeclaration':
|
||||
return InstantiateFunctionObject_AsyncFunctionDeclaration(AnyFunctionDeclaration, env, privateEnv);
|
||||
case 'AsyncGeneratorDeclaration':
|
||||
return InstantiateFunctionObject_AsyncGeneratorDeclaration(AnyFunctionDeclaration, env, privateEnv);
|
||||
|
||||
default:
|
||||
throw new OutOfRange('InstantiateFunctionObject', AnyFunctionDeclaration);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
import { surroundingAgent } from '../host-defined/engine.mts';
|
||||
import {
|
||||
Value, Descriptor, type PropertyKeyValue, PrivateName,
|
||||
} from '../value.mts';
|
||||
import { X } from '../completion.mts';
|
||||
import { StringValue } from '../static-semantics/all.mts';
|
||||
import type { ParseNode } from '../parser/ParseNode.mts';
|
||||
import {
|
||||
Assert,
|
||||
DefinePropertyOrThrow,
|
||||
OrdinaryFunctionCreate,
|
||||
OrdinaryObjectCreate,
|
||||
SetFunctionName,
|
||||
sourceTextMatchedBy,
|
||||
DeclarativeEnvironmentRecord,
|
||||
} from '#self';
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-runtime-semantics-instantiategeneratorfunctionexpression */
|
||||
// GeneratorExpression :
|
||||
// `function` `*` `(` FormalParameters `)` `{` GeneratorBody `}`
|
||||
// `function` `* `BindingIdentifier `(` FormalParameters `)` `{` GeneratorBody `}`
|
||||
export function InstantiateGeneratorFunctionExpression(GeneratorExpression: ParseNode.GeneratorExpression, name?: PropertyKeyValue | PrivateName) {
|
||||
const { BindingIdentifier, FormalParameters, GeneratorBody } = GeneratorExpression;
|
||||
if (BindingIdentifier) {
|
||||
// 1. Assert: name is not present.
|
||||
Assert(name === undefined);
|
||||
// 2. Set name to StringValue of BindingIdentifier.
|
||||
name = StringValue(BindingIdentifier);
|
||||
// 3. Let scope be the running execution context's LexicalEnvironment.
|
||||
const scope = surroundingAgent.runningExecutionContext.LexicalEnvironment;
|
||||
// 4. Let funcEnv be NewDeclarativeEnvironment(scope).
|
||||
const funcEnv = new DeclarativeEnvironmentRecord(scope);
|
||||
// 5. Perform funcEnv.CreateImmutableBinding(name, false).
|
||||
funcEnv.CreateImmutableBinding(name, Value.false);
|
||||
// 6. Let privateScope be the running execution context's PrivateEnvironment.
|
||||
const privateScope = surroundingAgent.runningExecutionContext.PrivateEnvironment;
|
||||
// 7. Let sourceText be the source text matched by GeneratorExpression.
|
||||
const sourceText = sourceTextMatchedBy(GeneratorExpression);
|
||||
// 8. Let closure be OrdinaryFunctionCreate(%GeneratorFunction.prototype%, sourceText, FormalParameters, GeneratorBody, non-lexical-this, funcEnv, privateScope).
|
||||
const closure = OrdinaryFunctionCreate(surroundingAgent.intrinsic('%GeneratorFunction.prototype%'), sourceText, FormalParameters, GeneratorBody, 'non-lexical-this', funcEnv, privateScope);
|
||||
// 9. Perform SetFunctionName(closure, name).
|
||||
SetFunctionName(closure, name);
|
||||
// 10. Let prototype be ! OrdinaryObjectCreate(%GeneratorFunction.prototype.prototype%).
|
||||
const prototype = X(OrdinaryObjectCreate(surroundingAgent.intrinsic('%GeneratorFunction.prototype.prototype%')));
|
||||
// 11. Perform DefinePropertyOrThrow(closure, "prototype", PropertyDescriptor { [[Value]]: prototype, [[Writable]]: true, [[Enumerable]]: false, [[Configurable]]: false }).
|
||||
X(DefinePropertyOrThrow(closure, Value('prototype'), new Descriptor({
|
||||
Value: prototype,
|
||||
Writable: Value.true,
|
||||
Enumerable: Value.false,
|
||||
Configurable: Value.false,
|
||||
})));
|
||||
// 12. Perform funcEnv.InitializeBinding(name, closure).
|
||||
X(funcEnv.InitializeBinding(name, closure));
|
||||
// 13. Return closure.
|
||||
return closure;
|
||||
}
|
||||
// 1. If name is not present, set name to "".
|
||||
if (name === undefined) {
|
||||
name = Value('');
|
||||
}
|
||||
// 2. Let scope be the running execution context's LexicalEnvironment.
|
||||
const scope = surroundingAgent.runningExecutionContext.LexicalEnvironment;
|
||||
// 3. Let privateScope be the running execution context's PrivateEnvironment.
|
||||
const privateScope = surroundingAgent.runningExecutionContext.PrivateEnvironment;
|
||||
// 4. Let sourceText be the source text matched by GeneratorExpression.
|
||||
const sourceText = sourceTextMatchedBy(GeneratorExpression);
|
||||
// 5. Let closure be OrdinaryFunctionCreate(%GeneratorFunction.prototype%, sourceText, FormalParameters, GeneratorBody, non-lexical-this, scope, privateScope).
|
||||
const closure = OrdinaryFunctionCreate(surroundingAgent.intrinsic('%GeneratorFunction.prototype%'), sourceText, FormalParameters, GeneratorBody, 'non-lexical-this', scope, privateScope);
|
||||
// 6. Perform SetFunctionName(closure, name).
|
||||
SetFunctionName(closure, name);
|
||||
// 7. Let prototype be ! OrdinaryObjectCreate(%GeneratorFunction.prototype.prototype%).
|
||||
const prototype = X(OrdinaryObjectCreate(surroundingAgent.intrinsic('%GeneratorFunction.prototype.prototype%')));
|
||||
// 8. Perform DefinePropertyOrThrow(closure, "prototype", PropertyDescriptor { [[Value]]: prototype, [[Writable]]: true, [[Enumerable]]: false, [[Configurable]]: false }).
|
||||
X(DefinePropertyOrThrow(closure, Value('prototype'), new Descriptor({
|
||||
Value: prototype,
|
||||
Writable: Value.true,
|
||||
Enumerable: Value.false,
|
||||
Configurable: Value.false,
|
||||
})));
|
||||
// 9. Return closure.
|
||||
return closure;
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
import { surroundingAgent } from '../host-defined/engine.mts';
|
||||
import { PrivateName, Value, type PropertyKeyValue } from '../value.mts';
|
||||
import { StringValue } from '../static-semantics/all.mts';
|
||||
import type { ParseNode } from '../parser/ParseNode.mts';
|
||||
import {
|
||||
Assert,
|
||||
OrdinaryFunctionCreate,
|
||||
SetFunctionName,
|
||||
MakeConstructor,
|
||||
sourceTextMatchedBy,
|
||||
DeclarativeEnvironmentRecord, X,
|
||||
} from '#self';
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-runtime-semantics-instantiateordinaryfunctionexpression */
|
||||
// FunctionExpression :
|
||||
// `function` `(` FormalParameters `)` `{` FunctionBody `}`
|
||||
// `function` BindingIdentifier `(` FormalParameters `)` `{` FunctionBody `}`
|
||||
export function InstantiateOrdinaryFunctionExpression(FunctionExpression: ParseNode.FunctionExpression, name?: PropertyKeyValue | PrivateName) {
|
||||
const { BindingIdentifier, FormalParameters, FunctionBody } = FunctionExpression;
|
||||
if (BindingIdentifier) {
|
||||
// 1. Assert: name is not present.
|
||||
Assert(name === undefined);
|
||||
// 2. Set name to StringValue of BindingIdentifier.
|
||||
name = StringValue(BindingIdentifier);
|
||||
// 3. Let scope be the running execution context's LexicalEnvironment.
|
||||
const scope = surroundingAgent.runningExecutionContext.LexicalEnvironment;
|
||||
// 4. Let funcEnv be NewDeclarativeEnvironment(scope).
|
||||
const funcEnv = new DeclarativeEnvironmentRecord(scope);
|
||||
// 5. Perform funcEnv.CreateImmutableBinding(name, false).
|
||||
funcEnv.CreateImmutableBinding(name, Value.false);
|
||||
// 6. Let privateScope be the running execution context's PrivateEnvironment.
|
||||
const privateScope = surroundingAgent.runningExecutionContext.PrivateEnvironment;
|
||||
// 7. Let sourceText be the source text matched by FunctionExpression.
|
||||
const sourceText = sourceTextMatchedBy(FunctionExpression);
|
||||
// 8. Let closure be OrdinaryFunctionCreate(%Function.prototype%, sourceText, FormalParameters, FunctionBody, non-lexical-this, funcEnv, privateScope).
|
||||
const closure = OrdinaryFunctionCreate(surroundingAgent.intrinsic('%Function.prototype%'), sourceText, FormalParameters, FunctionBody, 'non-lexical-this', funcEnv, privateScope);
|
||||
// 9. Perform SetFunctionName(closure, name).
|
||||
SetFunctionName(closure, name);
|
||||
// 10. Perform MakeConstructor(closure).
|
||||
MakeConstructor(closure);
|
||||
// 11. Perform funcEnv.InitializeBinding(name, closure).
|
||||
X(funcEnv.InitializeBinding(name, closure));
|
||||
// 12. Return closure.
|
||||
return closure;
|
||||
}
|
||||
// 1. If name is not present, set name to "".
|
||||
if (name === undefined) {
|
||||
name = Value('');
|
||||
}
|
||||
// 2. Let scope be the running execution context's LexicalEnvironment.
|
||||
const scope = surroundingAgent.runningExecutionContext.LexicalEnvironment;
|
||||
// 3. Let privateScope be the running execution context's PrivateEnvironment.
|
||||
const privateScope = surroundingAgent.runningExecutionContext.PrivateEnvironment;
|
||||
// 4. Let sourceText be the source text matched by FunctionExpression.
|
||||
const sourceText = sourceTextMatchedBy(FunctionExpression);
|
||||
// 5. Let closure be OrdinaryFunctionCreate(%Function.prototype%, sourceText, FormalParameters, FunctionBody, non-lexical-this, scope, privateScope).
|
||||
const closure = OrdinaryFunctionCreate(surroundingAgent.intrinsic('%Function.prototype%'), sourceText, FormalParameters, FunctionBody, 'non-lexical-this', scope, privateScope);
|
||||
// 6. Perform SetFunctionName(closure, name).
|
||||
SetFunctionName(closure, name);
|
||||
// 7. Perform MakeConstructor(closure).
|
||||
MakeConstructor(closure);
|
||||
// 8. Return closure.
|
||||
return closure;
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
import { Value } from '../value.mts';
|
||||
import { Evaluate } from '../evaluator.mts';
|
||||
import { StringValue, IsAnonymousFunctionDefinition } from '../static-semantics/all.mts';
|
||||
import { Q } from '../completion.mts';
|
||||
import type { ParseNode } from '../parser/ParseNode.mts';
|
||||
import {
|
||||
NamedEvaluation,
|
||||
BindingInitialization,
|
||||
} from './all.mts';
|
||||
import {
|
||||
GetV,
|
||||
GetValue,
|
||||
PutValue,
|
||||
ResolveBinding,
|
||||
InitializeReferencedBinding,
|
||||
} from '#self';
|
||||
import type {
|
||||
EnvironmentRecord, FunctionDeclaration, PropertyKeyValue, UndefinedValue,
|
||||
} from '#self';
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-runtime-semantics-keyedbindinginitialization */
|
||||
export function* KeyedBindingInitialization(node: ParseNode.BindingElement | ParseNode.SingleNameBinding, value: Value, environment: EnvironmentRecord | UndefinedValue, propertyName: PropertyKeyValue) {
|
||||
if (node.type === 'BindingElement') {
|
||||
// 1. Let v be ? GetV(value, propertyName).
|
||||
let v = Q(yield* GetV(value, propertyName));
|
||||
// 2. If Initializer is present and v is undefined, then
|
||||
if (node.Initializer && v === Value.undefined) {
|
||||
// a. Let defaultValue be the result of evaluating Initializer.
|
||||
const defaultValue = Q(yield* Evaluate(node.Initializer));
|
||||
// b. Set v to ? GetValue(defaultValue).
|
||||
v = Q(yield* GetValue(defaultValue));
|
||||
}
|
||||
// 2. Return the result of performing BindingInitialization for BindingPattern passing v and environment as arguments.
|
||||
return yield* BindingInitialization(node.BindingPattern, v, environment);
|
||||
} else {
|
||||
// 1. Let bindingId be StringValue of BindingIdentifier.
|
||||
const bindingId = StringValue(node.BindingIdentifier);
|
||||
// 2. Let lhs be ? ResolveBinding(bindingId, environment).
|
||||
const lhs = Q(yield* ResolveBinding(bindingId, environment, node.BindingIdentifier.strict));
|
||||
// 3. Let v be ? GetV(value, propertyName).
|
||||
let v = Q(yield* GetV(value, propertyName));
|
||||
if (node.Initializer && v === Value.undefined) {
|
||||
// a. If IsAnonymousFunctionDefinition(Initializer) is true, then
|
||||
if (IsAnonymousFunctionDefinition(node.Initializer)) {
|
||||
// i. Set v to the result of performing NamedEvaluation for Initializer with argument bindingId.
|
||||
v = (yield* NamedEvaluation(node.Initializer as FunctionDeclaration, bindingId)) as Value;
|
||||
} else { // b. Else,
|
||||
// i. Let defaultValue be the result of evaluating Initializer.
|
||||
const defaultValue = Q(yield* Evaluate(node.Initializer));
|
||||
// ii. Set v to ? GetValue(defaultValue).
|
||||
v = Q(yield* GetValue(defaultValue));
|
||||
}
|
||||
}
|
||||
// 5. If environment is undefined, return ? PutValue(lhs, v).
|
||||
if (environment === Value.undefined) {
|
||||
return Q(yield* PutValue(lhs, v));
|
||||
}
|
||||
// 6. Return InitializeReferencedBinding(lhs, v).
|
||||
return yield* InitializeReferencedBinding(lhs, v);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,753 @@
|
||||
import { surroundingAgent } from '../host-defined/engine.mts';
|
||||
import {
|
||||
JSStringValue, ObjectValue, ReferenceRecord, Value,
|
||||
} from '../value.mts';
|
||||
import {
|
||||
Evaluate, type Evaluator, type PlainEvaluator, type StatementEvaluator,
|
||||
} from '../evaluator.mts';
|
||||
import {
|
||||
BoundNames,
|
||||
IsConstantDeclaration,
|
||||
IsDestructuring,
|
||||
StringValue,
|
||||
type DestructuringParseNode,
|
||||
} from '../static-semantics/all.mts';
|
||||
import { CreateForInIterator, type ForInIteratorInstance } from '../intrinsics/ForInIteratorPrototype.mts';
|
||||
import {
|
||||
Completion,
|
||||
NormalCompletion,
|
||||
AbruptCompletion,
|
||||
UpdateEmpty,
|
||||
EnsureCompletion,
|
||||
Await,
|
||||
Q, X,
|
||||
type PlainCompletion,
|
||||
BreakCompletion,
|
||||
} from '../completion.mts';
|
||||
import { JSStringSet, OutOfRange } from '../helpers.mts';
|
||||
import type { ParseNode } from '../parser/ParseNode.mts';
|
||||
import {
|
||||
Evaluate_SwitchStatement,
|
||||
Evaluate_VariableDeclarationList,
|
||||
BindingInitialization,
|
||||
DestructuringAssignmentEvaluation,
|
||||
refineLeftHandSideExpression,
|
||||
} from './all.mts';
|
||||
import {
|
||||
Assert,
|
||||
Call,
|
||||
GetIterator,
|
||||
GetValue,
|
||||
PutValue,
|
||||
GetV,
|
||||
ResolveBinding,
|
||||
InitializeReferencedBinding,
|
||||
IteratorComplete,
|
||||
IteratorValue,
|
||||
IteratorClose,
|
||||
AsyncIteratorClose,
|
||||
ToBoolean,
|
||||
ToObject,
|
||||
SameValue,
|
||||
type IteratorRecord,
|
||||
} from '#self';
|
||||
import { DeclarativeEnvironmentRecord } from '#self';
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-loopcontinues */
|
||||
function LoopContinues(completion: Completion<Value | void>, labelSet: JSStringSet) {
|
||||
// 1. If completion.[[Type]] is normal, return true.
|
||||
if (completion.Type === 'normal') {
|
||||
return Value.true;
|
||||
}
|
||||
// 2. If completion.[[Type]] is not continue, return false.
|
||||
if (completion.Type !== 'continue') {
|
||||
return Value.false;
|
||||
}
|
||||
// 3. If completion.[[Target]] is empty, return true.
|
||||
if (completion.Target === undefined) {
|
||||
return Value.true;
|
||||
}
|
||||
// 4. If completion.[[Target]] is an element of labelSet, return true.
|
||||
if (labelSet.has(completion.Target)) {
|
||||
return Value.true;
|
||||
}
|
||||
// 5. Return false.
|
||||
return Value.false;
|
||||
}
|
||||
|
||||
export function LabelledEvaluation(node: ParseNode.LabelledStatement | ParseNode.BreakableStatement, labelSet: JSStringSet): StatementEvaluator {
|
||||
switch (node.type) {
|
||||
case 'DoWhileStatement':
|
||||
case 'WhileStatement':
|
||||
case 'ForStatement':
|
||||
case 'ForInStatement':
|
||||
case 'ForOfStatement':
|
||||
case 'ForAwaitStatement':
|
||||
case 'SwitchStatement':
|
||||
return LabelledEvaluation_BreakableStatement(node, labelSet);
|
||||
case 'LabelledStatement':
|
||||
return LabelledEvaluation_LabelledStatement(node, labelSet);
|
||||
default:
|
||||
throw new OutOfRange('LabelledEvaluation', node);
|
||||
}
|
||||
}
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-labelled-statements-runtime-semantics-labelledevaluation */
|
||||
// LabelledStatement : LabelIdentifier `:` LabelledItem
|
||||
function* LabelledEvaluation_LabelledStatement({ LabelIdentifier, LabelledItem }: ParseNode.LabelledStatement, labelSet: JSStringSet) {
|
||||
// 1. Let label be the StringValue of LabelIdentifier.
|
||||
const label = StringValue(LabelIdentifier);
|
||||
// 2. Append label as an element of labelSet.
|
||||
labelSet.add(label);
|
||||
// 3. Let stmtResult be LabelledEvaluation of LabelledItem with argument labelSet.
|
||||
let stmtResult = EnsureCompletion(yield* LabelledEvaluation_LabelledItem(LabelledItem, labelSet)) as Completion<Value | void>;
|
||||
// 4. If stmtResult.[[Type]] is break and SameValue(stmtResult.[[Target]], label) is true, then
|
||||
if (stmtResult.Type === 'break' && SameValue(stmtResult.Target!, label) === Value.true) {
|
||||
// a. Set stmtResult to NormalCompletion(stmtResult.[[Value]]).
|
||||
stmtResult = NormalCompletion(stmtResult.Value);
|
||||
}
|
||||
// 5. Return Completion(stmtResult).
|
||||
return Completion(stmtResult);
|
||||
}
|
||||
|
||||
// LabelledItem :
|
||||
// Statement
|
||||
// FunctionDeclaration
|
||||
function LabelledEvaluation_LabelledItem(LabelledItem: ParseNode.LabelledItem, labelSet: JSStringSet) {
|
||||
switch (LabelledItem.type) {
|
||||
case 'DoWhileStatement':
|
||||
case 'WhileStatement':
|
||||
case 'ForStatement':
|
||||
case 'ForInStatement':
|
||||
case 'ForOfStatement':
|
||||
case 'SwitchStatement':
|
||||
case 'LabelledStatement':
|
||||
return LabelledEvaluation(LabelledItem, labelSet);
|
||||
default:
|
||||
return Evaluate(LabelledItem);
|
||||
}
|
||||
}
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-statement-semantics-runtime-semantics-labelledevaluation */
|
||||
// BreakableStatement :
|
||||
// IterationStatement
|
||||
// SwitchStatement
|
||||
//
|
||||
// IterationStatement :
|
||||
// (DoWhileStatement)
|
||||
// (WhileStatement)
|
||||
function* LabelledEvaluation_BreakableStatement(BreakableStatement: ParseNode.BreakableStatement, labelSet: JSStringSet): StatementEvaluator {
|
||||
switch (BreakableStatement.type) {
|
||||
case 'DoWhileStatement':
|
||||
case 'WhileStatement':
|
||||
case 'ForStatement':
|
||||
case 'ForInStatement':
|
||||
case 'ForOfStatement':
|
||||
case 'ForAwaitStatement': {
|
||||
// 1. Let stmtResult be LabelledEvaluation of IterationStatement with argument labelSet.
|
||||
let stmtResult = EnsureCompletion(yield* LabelledEvaluation_IterationStatement(BreakableStatement, labelSet));
|
||||
// 2. If stmtResult.[[Type]] is break, then
|
||||
if (stmtResult.Type === 'break') {
|
||||
// a. If stmtResult.[[Target]] is empty, then
|
||||
if (stmtResult.Target === undefined) {
|
||||
// i. If stmtResult.[[Value]] is empty, set stmtResult to NormalCompletion(undefined).
|
||||
if (stmtResult.Value === undefined) {
|
||||
stmtResult = NormalCompletion(Value.undefined);
|
||||
} else { // ii. Else, set stmtResult to NormalCompletion(stmtResult.[[Value]]).
|
||||
stmtResult = NormalCompletion(stmtResult.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
// 3. Return Completion(stmtResult).
|
||||
return Completion(stmtResult);
|
||||
}
|
||||
case 'SwitchStatement': {
|
||||
// 1. Let stmtResult be LabelledEvaluation of SwitchStatement.
|
||||
let stmtResult = EnsureCompletion(yield* Evaluate_SwitchStatement(BreakableStatement));
|
||||
// 2. If stmtResult.[[Type]] is break, then
|
||||
if (stmtResult.Type === 'break') {
|
||||
// a. If stmtResult.[[Target]] is empty, then
|
||||
if (stmtResult.Target === undefined) {
|
||||
// i. If stmtResult.[[Value]] is empty, set stmtResult to NormalCompletion(undefined).
|
||||
if (stmtResult.Value === undefined) {
|
||||
stmtResult = NormalCompletion(Value.undefined);
|
||||
} else { // ii. Else, set stmtResult to NormalCompletion(stmtResult.[[Value]]).
|
||||
stmtResult = NormalCompletion(stmtResult.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
// 3. Return Completion(stmtResult).
|
||||
return Completion(stmtResult) as Completion<Value | void>;
|
||||
}
|
||||
default:
|
||||
throw new OutOfRange('LabelledEvaluation_BreakableStatement', BreakableStatement);
|
||||
}
|
||||
}
|
||||
|
||||
function LabelledEvaluation_IterationStatement(IterationStatement: ParseNode.IterationStatement, labelSet: JSStringSet): StatementEvaluator {
|
||||
switch (IterationStatement.type) {
|
||||
case 'DoWhileStatement':
|
||||
return LabelledEvaluation_IterationStatement_DoWhileStatement(IterationStatement, labelSet);
|
||||
case 'WhileStatement':
|
||||
return LabelledEvaluation_IterationStatement_WhileStatement(IterationStatement, labelSet);
|
||||
case 'ForStatement':
|
||||
return LabelledEvaluation_BreakableStatement_ForStatement(IterationStatement, labelSet);
|
||||
case 'ForInStatement':
|
||||
return LabelledEvaluation_IterationStatement_ForInStatement(IterationStatement, labelSet);
|
||||
case 'ForOfStatement':
|
||||
return LabelledEvaluation_IterationStatement_ForOfStatement(IterationStatement, labelSet);
|
||||
case 'ForAwaitStatement':
|
||||
return LabelledEvaluation_IterationStatement_ForAwaitStatement(IterationStatement, labelSet);
|
||||
default:
|
||||
throw new OutOfRange('LabelledEvaluation_IterationStatement', IterationStatement);
|
||||
}
|
||||
}
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-do-while-statement-runtime-semantics-labelledevaluation */
|
||||
// IterationStatement :
|
||||
// `do` Statement `while` `(` Expression `)` `;`
|
||||
function* LabelledEvaluation_IterationStatement_DoWhileStatement({ Statement, Expression }: ParseNode.DoWhileStatement, labelSet: JSStringSet) {
|
||||
// 1. Let V be undefined.
|
||||
let V: Value = Value.undefined;
|
||||
// 2. Repeat,
|
||||
while (true) {
|
||||
// a. Let stmtResult be the result of evaluating Statement.
|
||||
const stmtResult = EnsureCompletion(yield* Evaluate(Statement)) as Completion<Value | void>;
|
||||
// b. If LoopContinues(stmtResult, labelSet) is false, return Completion(UpdateEmpty(stmtResult, V)).
|
||||
if (LoopContinues(stmtResult, labelSet) === Value.false) {
|
||||
return Completion(UpdateEmpty(stmtResult, V));
|
||||
}
|
||||
// c. If stmtResult.[[Value]] is not empty, set V to stmtResult.[[Value]].
|
||||
if (stmtResult.Value !== undefined) {
|
||||
V = stmtResult.Value;
|
||||
}
|
||||
// d. Let exprRef be the result of evaluating Expression.
|
||||
const exprRef = Q(yield* Evaluate(Expression));
|
||||
// e. Let exprValue be ? GetValue(exprRef).
|
||||
const exprValue = Q(yield* GetValue(exprRef));
|
||||
// f. If ! ToBoolean(exprValue) is false, return NormalCompletion(V).
|
||||
if (X(ToBoolean(exprValue)) === Value.false) {
|
||||
return NormalCompletion(V);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-while-statement-runtime-semantics-labelledevaluation */
|
||||
// IterationStatement :
|
||||
// `while` `(` Expression `)` Statement
|
||||
function* LabelledEvaluation_IterationStatement_WhileStatement({ Expression, Statement }: ParseNode.WhileStatement, labelSet: JSStringSet) {
|
||||
// 1. Let V be undefined.
|
||||
let V: Value = Value.undefined;
|
||||
// 2. Repeat,
|
||||
while (true) {
|
||||
// a. Let exprRef be the result of evaluating Expression.
|
||||
const exprRef = Q(yield* Evaluate(Expression));
|
||||
// b. Let exprValue be ? GetValue(exprRef).
|
||||
const exprValue = Q(yield* GetValue(exprRef));
|
||||
// c. If ! ToBoolean(exprValue) is false, return NormalCompletion(V).
|
||||
if (X(ToBoolean(exprValue)) === Value.false) {
|
||||
return NormalCompletion(V);
|
||||
}
|
||||
// d. Let stmtResult be the result of evaluating Statement.
|
||||
const stmtResult = EnsureCompletion(yield* Evaluate(Statement));
|
||||
// e. If LoopContinues(stmtResult, labelSet) is false, return Completion(UpdateEmpty(stmtResult, V)).
|
||||
if (LoopContinues(stmtResult, labelSet) === Value.false) {
|
||||
return Completion(UpdateEmpty(stmtResult, V));
|
||||
}
|
||||
// f. If stmtResult.[[Value]] is not empty, set V to stmtResult.[[Value]].
|
||||
if (stmtResult.Value !== undefined) {
|
||||
V = stmtResult.Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-for-statement-runtime-semantics-labelledevaluation */
|
||||
// IterationStatement :
|
||||
// `for` `(` Expression? `;` Expression? `;` Expresssion? `)` Statement
|
||||
// `for` `(` `var` VariableDeclarationList `;` Expression? `;` Expression? `)` Statement
|
||||
// `for` `(` LexicalDeclaration Expression? `;` Expression? `)` Statement
|
||||
function* LabelledEvaluation_BreakableStatement_ForStatement(ForStatement: ParseNode.ForStatement, labelSet: JSStringSet) {
|
||||
const {
|
||||
VariableDeclarationList, LexicalDeclaration,
|
||||
Expression_a, Expression_b, Expression_c,
|
||||
Statement,
|
||||
} = ForStatement;
|
||||
switch (true) {
|
||||
case !!LexicalDeclaration: {
|
||||
// 1. Let oldEnv be the running execution context's LexicalEnvironment.
|
||||
const oldEnv = surroundingAgent.runningExecutionContext.LexicalEnvironment;
|
||||
// 2. Let loopEnv be NewDeclarativeEnvironment(oldEnv).
|
||||
const loopEnv = new DeclarativeEnvironmentRecord(oldEnv);
|
||||
// 3. Let isConst be IsConstantDeclaration of LexicalDeclaration.
|
||||
const isConst = IsConstantDeclaration(LexicalDeclaration);
|
||||
// 4. Let boundNames be the BoundNames of LexicalDeclaration.
|
||||
const boundNames = BoundNames(LexicalDeclaration);
|
||||
// 5. For each element dn of boundNames, do
|
||||
for (const dn of boundNames) {
|
||||
// a. If isConst is true, then
|
||||
if (isConst) {
|
||||
// i. Perform ! loopEnv.CreateImmutableBinding(dn, true).
|
||||
X(loopEnv.CreateImmutableBinding(dn, Value.true));
|
||||
} else { // b. Else,
|
||||
// i. Perform ! loopEnv.CreateMutableBinding(dn, false).
|
||||
X(loopEnv.CreateMutableBinding(dn, Value.false));
|
||||
}
|
||||
}
|
||||
// 6. Set the running execution context's LexicalEnvironment to loopEnv.
|
||||
surroundingAgent.runningExecutionContext.LexicalEnvironment = loopEnv;
|
||||
// 7. Let forDcl be the result of evaluating LexicalDeclaration.
|
||||
const forDcl = yield* Evaluate(LexicalDeclaration);
|
||||
// 8. If forDcl is an abrupt completion, then
|
||||
if (forDcl instanceof AbruptCompletion) {
|
||||
// a. Set the running execution context's LexicalEnvironment to oldEnv.
|
||||
surroundingAgent.runningExecutionContext.LexicalEnvironment = oldEnv;
|
||||
// b. Return Completion(forDcl).
|
||||
return Completion(forDcl);
|
||||
}
|
||||
// 9. If isConst is false, let perIterationLets be boundNames; otherwise let perIterationLets be « ».
|
||||
let perIterationLets: JSStringValue[];
|
||||
if (isConst === false) {
|
||||
perIterationLets = boundNames;
|
||||
} else {
|
||||
perIterationLets = [];
|
||||
}
|
||||
// 10. Let bodyResult be ForBodyEvaluation(the first Expression, the second Expression, Statement, perIterationLets, labelSet).
|
||||
const bodyResult = yield* ForBodyEvaluation(Expression_a, Expression_b, Statement, perIterationLets, labelSet);
|
||||
// 11. Set the running execution context's LexicalEnvironment to oldEnv.
|
||||
surroundingAgent.runningExecutionContext.LexicalEnvironment = oldEnv;
|
||||
// 12. Return Completion(bodyResult).
|
||||
return Completion(bodyResult);
|
||||
}
|
||||
case !!VariableDeclarationList: {
|
||||
// 1. Let varDcl be the result of evaluating VariableDeclarationList.
|
||||
const varDcl = yield* Evaluate_VariableDeclarationList(VariableDeclarationList);
|
||||
Q(varDcl);
|
||||
// 3. Return ? ForBodyEvaluation(the first Expression, the second Expression, Statement, « », labelSet).
|
||||
return Q(yield* ForBodyEvaluation(Expression_a, Expression_b, Statement, [], labelSet));
|
||||
}
|
||||
default: {
|
||||
// 1. If the first Expression is present, then
|
||||
if (Expression_a) {
|
||||
// a. Let exprRef be the result of evaluating the first Expression.
|
||||
const exprRef = Q(yield* Evaluate(Expression_a));
|
||||
// b. Perform ? GetValue(exprRef).
|
||||
Q(yield* GetValue(exprRef));
|
||||
}
|
||||
// 2. Return ? ForBodyEvaluation(the second Expression, the third Expression, Statement, « », labelSet).
|
||||
return Q(yield* ForBodyEvaluation(Expression_b, Expression_c, Statement, [], labelSet));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function* LabelledEvaluation_IterationStatement_ForInStatement(ForInStatement: ParseNode.ForInStatement, labelSet: JSStringSet): StatementEvaluator {
|
||||
const {
|
||||
LeftHandSideExpression,
|
||||
ForBinding,
|
||||
ForDeclaration,
|
||||
Expression,
|
||||
Statement,
|
||||
} = ForInStatement;
|
||||
switch (true) {
|
||||
case !!LeftHandSideExpression && !!Expression: {
|
||||
// IterationStatement : `for` `(` LeftHandSideExpression `in` Expression `)` Statement
|
||||
// 1. Let keyResult be ? ForIn/OfHeadEvaluation(« », Expression, enumerate).
|
||||
const keyResult = Q(yield* ForInOfHeadEvaluation([], Expression, 'enumerate'));
|
||||
// 2. Return ? ForIn/OfBodyEvaluation(LeftHandSideExpression, Statement, keyResult, enumerate, assignment, labelSet).
|
||||
return Q(yield* ForInOfBodyEvaluation(LeftHandSideExpression, Statement, keyResult as IteratorRecord, 'enumerate', 'assignment', labelSet));
|
||||
}
|
||||
case !!ForBinding && !!Expression: {
|
||||
// IterationStatement :`for` `(` `var` ForBinding `in` Expression `)` Statement
|
||||
// 1. Let keyResult be ? ForIn/OfHeadEvaluation(« », Expression, enumerate).
|
||||
const keyResult = Q(yield* ForInOfHeadEvaluation([], Expression, 'enumerate'));
|
||||
// 2. Return ? ForIn/OfBodyEvaluation(ForBinding, Statement, keyResult, enumerate, varBinding, labelSet).
|
||||
return Q(yield* ForInOfBodyEvaluation(ForBinding, Statement, keyResult as IteratorRecord, 'enumerate', 'varBinding', labelSet));
|
||||
}
|
||||
case !!ForDeclaration && !!Expression: {
|
||||
// IterationStatement : `for` `(` ForDeclaration `in` Expression `)` Statement
|
||||
// 1. Let keyResult be ? ForIn/OfHeadEvaluation(BoundNames of ForDeclaration, Expression, enumerate).
|
||||
const keyResult = Q(yield* ForInOfHeadEvaluation(BoundNames(ForDeclaration), Expression, 'enumerate'));
|
||||
// 2. Return ? ForIn/OfBodyEvaluation(ForDeclaration, Statement, keyResult, enumerate, lexicalBinding, labelSet).
|
||||
return Q(yield* ForInOfBodyEvaluation(ForDeclaration, Statement, keyResult as IteratorRecord, 'enumerate', 'lexicalBinding', labelSet));
|
||||
}
|
||||
default:
|
||||
throw new OutOfRange('LabelledEvaluation_IterationStatement_ForInStatement', ForInStatement);
|
||||
}
|
||||
}
|
||||
|
||||
// IterationStatement :
|
||||
// `for` `await` `(` LeftHandSideExpression `of` AssignmentExpression `)` Statement
|
||||
// `for` `await` `(` `var` ForBinding `of` AssignmentExpression `)` Statement
|
||||
// `for` `await` `(` ForDeclaration`of` AssignmentExpression `)` Statement
|
||||
function* LabelledEvaluation_IterationStatement_ForAwaitStatement(ForAwaitStatement: ParseNode.ForAwaitStatement, labelSet: JSStringSet): StatementEvaluator {
|
||||
const {
|
||||
LeftHandSideExpression,
|
||||
ForBinding,
|
||||
ForDeclaration,
|
||||
AssignmentExpression,
|
||||
Statement,
|
||||
} = ForAwaitStatement;
|
||||
switch (true) {
|
||||
case !!LeftHandSideExpression: {
|
||||
// 1. Let keyResult be ? ForIn/OfHeadEvaluation(« », AssignmentExpression, async-iterate).
|
||||
const keyResult = Q(yield* ForInOfHeadEvaluation([], AssignmentExpression, 'async-iterate'));
|
||||
// 2. Return ? ForIn/OfBodyEvaluation(LeftHandSideExpression, Statement, keyResult, iterate, assignment, labelSet, async).
|
||||
return Q(yield* ForInOfBodyEvaluation(LeftHandSideExpression, Statement, keyResult as IteratorRecord, 'iterate', 'assignment', labelSet, 'async'));
|
||||
}
|
||||
case !!ForBinding: {
|
||||
// 1. Let keyResult be ? ForIn/OfHeadEvaluation(« », AssignmentExpression, async-iterate).
|
||||
const keyResult = Q(yield* ForInOfHeadEvaluation([], AssignmentExpression, 'async-iterate'));
|
||||
// 2. Return ? ForIn/OfBodyEvaluation(ForBinding, Statement, keyResult, iterate, varBinding, labelSet, async).
|
||||
return Q(yield* ForInOfBodyEvaluation(ForBinding, Statement, keyResult as IteratorRecord, 'iterate', 'varBinding', labelSet, 'async'));
|
||||
}
|
||||
case !!ForDeclaration: {
|
||||
// 1. Let keyResult be ? ForIn/OfHeadEvaluation(BoundNames of ForDeclaration, AssignmentExpression, async-iterate).
|
||||
const keyResult = Q(yield* ForInOfHeadEvaluation(BoundNames(ForDeclaration), AssignmentExpression, 'async-iterate'));
|
||||
// 2. Return ? ForIn/OfBodyEvaluation(ForDeclaration, Statement, keyResult, iterate, lexicalBinding, labelSet, async).
|
||||
return Q(yield* ForInOfBodyEvaluation(ForDeclaration, Statement, keyResult as IteratorRecord, 'iterate', 'lexicalBinding', labelSet, 'async'));
|
||||
}
|
||||
default:
|
||||
throw new OutOfRange('LabelledEvaluation_IterationStatement_ForAwaitStatement', ForAwaitStatement);
|
||||
}
|
||||
}
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-for-in-and-for-of-statements-runtime-semantics-labelledevaluation */
|
||||
// IterationStatement :
|
||||
// `for` `(` LeftHandSideExpression `of` AssignmentExpression `)` Statement
|
||||
// `for` `(` `var` ForBinding `of` AssignmentExpression `)` Statement
|
||||
// `for` `(` ForDeclaration `of` AssignmentExpression `)` Statement
|
||||
function* LabelledEvaluation_IterationStatement_ForOfStatement(ForOfStatement: ParseNode.ForOfStatement, labelSet: JSStringSet): StatementEvaluator {
|
||||
const {
|
||||
LeftHandSideExpression,
|
||||
ForBinding,
|
||||
ForDeclaration,
|
||||
AssignmentExpression,
|
||||
Statement,
|
||||
} = ForOfStatement;
|
||||
switch (true) {
|
||||
case !!LeftHandSideExpression: {
|
||||
// 1. Let keyResult be ? ForIn/OfHeadEvaluation(« », AssignmentExpression, iterate).
|
||||
const keyResult = Q(yield* ForInOfHeadEvaluation([], AssignmentExpression, 'iterate'));
|
||||
// 2. Return ? ForIn/OfBodyEvaluation(LeftHandSideExpression, Statement, keyResult, iterate, assignment, labelSet).
|
||||
return Q(yield* ForInOfBodyEvaluation(LeftHandSideExpression, Statement, keyResult as IteratorRecord, 'iterate', 'assignment', labelSet));
|
||||
}
|
||||
case !!ForBinding: {
|
||||
// 1. Let keyResult be ? ForIn/OfHeadEvaluation(« », AssignmentExpression, iterate).
|
||||
const keyResult = Q(yield* ForInOfHeadEvaluation([], AssignmentExpression, 'iterate'));
|
||||
// 2. Return ? ForIn/OfBodyEvaluation(ForBinding, Statement, keyResult, iterate, varBinding, labelSet).
|
||||
return Q(yield* ForInOfBodyEvaluation(ForBinding, Statement, keyResult as IteratorRecord, 'iterate', 'varBinding', labelSet));
|
||||
}
|
||||
case !!ForDeclaration: {
|
||||
// 1. Let keyResult be ? ForIn/OfHeadEvaluation(BoundNames of ForDeclaration, AssignmentExpression, iterate).
|
||||
const keyResult = Q(yield* ForInOfHeadEvaluation(BoundNames(ForDeclaration), AssignmentExpression, 'iterate'));
|
||||
// 2. Return ? ForIn/OfBodyEvaluation(ForDeclaration, Statement, keyResult, iterate, lexicalBinding, labelSet).
|
||||
return Q(yield* ForInOfBodyEvaluation(ForDeclaration, Statement, keyResult as IteratorRecord, 'iterate', 'lexicalBinding', labelSet));
|
||||
}
|
||||
default:
|
||||
throw new OutOfRange('LabelledEvaluation_BreakableStatement_ForOfStatement', ForOfStatement);
|
||||
}
|
||||
}
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-forbodyevaluation */
|
||||
function* ForBodyEvaluation(test: ParseNode.Expression | undefined, increment: ParseNode.Expression | undefined, stmt: ParseNode.Statement, perIterationBindings: readonly JSStringValue[], labelSet: JSStringSet) {
|
||||
// 1. Let V be undefined.
|
||||
let V: Value = Value.undefined;
|
||||
// 2. Perform ? CreatePerIterationEnvironment(perIterationBindings).
|
||||
Q(yield* CreatePerIterationEnvironment(perIterationBindings));
|
||||
// 3. Repeat,
|
||||
while (true) {
|
||||
// a. If test is not [empty], then
|
||||
if (test) {
|
||||
// i. Let testRef be the result of evaluating test.
|
||||
const testRef = Q(yield* Evaluate(test));
|
||||
// ii. Let testValue be ? GetValue(testRef).
|
||||
const testValue = Q(yield* GetValue(testRef));
|
||||
// iii. If ! ToBoolean(testValue) is false, return NormalCompletion(V).
|
||||
if (X(ToBoolean(testValue)) === Value.false) {
|
||||
return NormalCompletion(V);
|
||||
}
|
||||
}
|
||||
// b. Let result be the result of evaluating stmt.
|
||||
const result = EnsureCompletion(yield* Evaluate(stmt));
|
||||
// c. If LoopContinues(result, labelSet) is false, return Completion(UpdateEmpty(result, V)).
|
||||
if (LoopContinues(result, labelSet) === Value.false) {
|
||||
return Completion(UpdateEmpty(result, V));
|
||||
}
|
||||
// d. If result.[[Value]] is not empty, set V to result.[[Value]].
|
||||
if (result.Value !== undefined) {
|
||||
V = result.Value;
|
||||
}
|
||||
// e. Perform ? CreatePerIterationEnvironment(perIterationBindings).
|
||||
Q(yield* CreatePerIterationEnvironment(perIterationBindings));
|
||||
// f. If increment is not [empty], then
|
||||
if (increment) {
|
||||
// i. Let incRef be the result of evaluating increment.
|
||||
const incRef = Q(yield* Evaluate(increment));
|
||||
// ii. Perform ? GetValue(incRef).
|
||||
Q(yield* GetValue(incRef));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-createperiterationenvironment */
|
||||
function* CreatePerIterationEnvironment(perIterationBindings: readonly JSStringValue[]): PlainEvaluator {
|
||||
// 1. If perIterationBindings has any elements, then
|
||||
if (perIterationBindings.length > 0) {
|
||||
// a. Let lastIterationEnv be the running execution context's LexicalEnvironment.
|
||||
const lastIterationEnv = surroundingAgent.runningExecutionContext.LexicalEnvironment;
|
||||
// b. Let outer be lastIterationEnv.[[OuterEnv]].
|
||||
const outer = lastIterationEnv.OuterEnv;
|
||||
// c. Assert: outer is not null.
|
||||
Assert(outer !== Value.null);
|
||||
// d. Let thisIterationEnv be NewDeclarativeEnvironment(outer).
|
||||
const thisIterationEnv = new DeclarativeEnvironmentRecord(outer);
|
||||
// e. For each element bn of perIterationBindings, do
|
||||
for (const bn of perIterationBindings) {
|
||||
// i. Perform ! thisIterationEnv.CreateMutableBinding(bn, false).
|
||||
X(thisIterationEnv.CreateMutableBinding(bn, Value.false));
|
||||
// ii. Let lastValue be ? lastIterationEnv.GetBindingValue(bn, true).
|
||||
const lastValue = Q(yield* lastIterationEnv.GetBindingValue(bn, Value.true));
|
||||
// iii. Perform thisIterationEnv.InitializeBinding(bn, lastValue).
|
||||
yield* thisIterationEnv.InitializeBinding(bn, lastValue);
|
||||
}
|
||||
// f. Set the running execution context's LexicalEnvironment to thisIterationEnv.
|
||||
surroundingAgent.runningExecutionContext.LexicalEnvironment = thisIterationEnv;
|
||||
}
|
||||
// 2. Return undefined.
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-runtime-semantics-forinofheadevaluation */
|
||||
function* ForInOfHeadEvaluation(uninitializedBoundNames: readonly JSStringValue[], expr: ParseNode.Expression | ParseNode.AssignmentExpression, iterationKind: 'enumerate' | 'iterate' | 'async-iterate'): Evaluator<PlainCompletion<Value | ForInOfHeadEvaluationResult | IteratorRecord> | BreakCompletion> {
|
||||
// 1. Let oldEnv be the running execution context's LexicalEnvironment.
|
||||
const oldEnv = surroundingAgent.runningExecutionContext.LexicalEnvironment;
|
||||
// 2. If uninitializedBoundNames is not an empty List, then
|
||||
if (uninitializedBoundNames.length > 0) {
|
||||
// a. Assert: uninitializedBoundNames has no duplicate entries.
|
||||
// b. Let newEnv be NewDeclarativeEnvironment(oldEnv).
|
||||
const newEnv = new DeclarativeEnvironmentRecord(oldEnv);
|
||||
// c. For each string name in uninitializedBoundNames, do
|
||||
for (const name of uninitializedBoundNames) {
|
||||
// i. Perform ! newEnv.CreateMutableBinding(name, false).
|
||||
X(newEnv.CreateMutableBinding(name, Value.false));
|
||||
}
|
||||
// d. Set the running execution context's LexicalEnvironment to newEnv.
|
||||
surroundingAgent.runningExecutionContext.LexicalEnvironment = newEnv;
|
||||
}
|
||||
// 3. Let exprRef be the result of evaluating expr.
|
||||
const exprRef = Q(yield* Evaluate(expr));
|
||||
// 4. Set the running execution context's LexicalEnvironment to oldEnv.
|
||||
surroundingAgent.runningExecutionContext.LexicalEnvironment = oldEnv;
|
||||
// 5. Let exprValue be ? GetValue(exprRef).
|
||||
const exprValue = Q(yield* GetValue(exprRef));
|
||||
// 6. If iterationKind is enumerate, then
|
||||
if (iterationKind === 'enumerate') {
|
||||
// a. If exprValue is undefined or null, then
|
||||
if (exprValue === Value.undefined || exprValue === Value.null) {
|
||||
// i. Return Completion { [[Type]]: break, [[Value]]: empty, [[Target]]: empty }.
|
||||
return new Completion({ Type: 'break', Value: undefined, Target: undefined });
|
||||
}
|
||||
// b. Let obj be ! ToObject(exprValue).
|
||||
const obj = X(ToObject(exprValue));
|
||||
// c. Let iterator be ? EnumerateObjectProperties(obj).
|
||||
const iterator = Q(EnumerateObjectProperties(obj));
|
||||
// d. Let nextMethod be ! GetV(iterator, "next").
|
||||
const nextMethod = X(GetV(iterator, Value('next')));
|
||||
// e. Return the Record { [[Iterator]]: iterator, [[NextMethod]]: nextMethod, [[Done]]: false }.
|
||||
return { Iterator: iterator, NextMethod: nextMethod, Done: Value.false };
|
||||
} else { // 7. Else,
|
||||
// a. Assert: iterationKind is iterate or async-iterate.
|
||||
Assert(iterationKind === 'iterate' || iterationKind === 'async-iterate');
|
||||
// b. If iterationKind is async-iterate, let iteratorHint be async.
|
||||
// c. Else, let iteratorHint be sync.
|
||||
const iteratorHint = iterationKind === 'async-iterate' ? 'async' : 'sync';
|
||||
// d. Return ? GetIterator(exprValue, iteratorHint).
|
||||
return Q(yield* GetIterator(exprValue, iteratorHint));
|
||||
}
|
||||
}
|
||||
interface ForInOfHeadEvaluationResult {
|
||||
readonly Iterator: ForInIteratorInstance;
|
||||
readonly NextMethod: Value;
|
||||
readonly Done: Value;
|
||||
}
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-enumerate-object-properties */
|
||||
function EnumerateObjectProperties(O: ObjectValue) {
|
||||
return CreateForInIterator(O);
|
||||
}
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-runtime-semantics-forin-div-ofbodyevaluation-lhs-stmt-iterator-lhskind-labelset */
|
||||
function* ForInOfBodyEvaluation(lhs: ParseNode, stmt: ParseNode.Statement, iteratorRecord: IteratorRecord, iterationKind: 'enumerate' | 'iterate', lhsKind: 'assignment' | 'lexicalBinding' | 'varBinding', labelSet: JSStringSet, iteratorKind?: 'sync' | 'async'): StatementEvaluator {
|
||||
// 1. If iteratorKind is not present, set iteratorKind to sync.
|
||||
if (iteratorKind === undefined) {
|
||||
iteratorKind = 'sync';
|
||||
}
|
||||
// 2. Let oldEnv be the running execution context's LexicalEnvironment.
|
||||
const oldEnv = surroundingAgent.runningExecutionContext.LexicalEnvironment;
|
||||
// 3. Let V be undefined.
|
||||
let V: Value = Value.undefined;
|
||||
// 4. Let destructuring be IsDestructuring of lhs.
|
||||
const destructuring = IsDestructuring(lhs);
|
||||
// 5. If destructuring is true and if lhsKind is assignment, then
|
||||
let assignmentPattern;
|
||||
if (destructuring && lhsKind === 'assignment') {
|
||||
// a. Assert: lhs is a LeftHandSideExpression.
|
||||
// b. Let assignmentPattern be the AssignmentPattern that is covered by lhs.
|
||||
assignmentPattern = refineLeftHandSideExpression(lhs as DestructuringParseNode);
|
||||
}
|
||||
// 6. Repeat,
|
||||
while (true) {
|
||||
// a. Let nextResult be ? Call(iteratorRecord.[[NextMethod]], iteratorRecord.[[Iterator]]).
|
||||
let nextResult = Q(yield* Call(iteratorRecord.NextMethod, iteratorRecord.Iterator));
|
||||
// b. If iteratorKind is async, then set nextResult to ? Await(nextResult).
|
||||
if (iteratorKind === 'async') {
|
||||
nextResult = Q(yield* Await(nextResult));
|
||||
}
|
||||
// c. If Type(nextResult) is not Object, throw a TypeError exception.
|
||||
if (!(nextResult instanceof ObjectValue)) {
|
||||
return surroundingAgent.Throw('TypeError', 'NotAnObject', nextResult);
|
||||
}
|
||||
// d. Let done be ? IteratorComplete(nextResult).
|
||||
const done = Q(yield* IteratorComplete(nextResult));
|
||||
// e. If done is true, return NormalCompletion(V).
|
||||
if (done === Value.true) {
|
||||
return NormalCompletion(V);
|
||||
}
|
||||
// f. Let nextValue be ? IteratorValue(nextResult).
|
||||
const nextValue = Q(yield* IteratorValue(nextResult));
|
||||
// g. If lhsKind is either assignment or varBinding, then
|
||||
let lhsRef;
|
||||
let iterationEnv;
|
||||
if (lhsKind === 'assignment' || lhsKind === 'varBinding') {
|
||||
// i. If destructuring is false, then
|
||||
if (destructuring === false) {
|
||||
// 1. Let lhsRef be the result of evaluating lhs. (It may be evaluated repeatedly.)
|
||||
lhsRef = yield* Evaluate(lhs);
|
||||
}
|
||||
} else { // h. Else,
|
||||
// i. Assert: lhsKind is lexicalBinding.
|
||||
Assert(lhsKind === 'lexicalBinding');
|
||||
// ii. Assert: lhs is a ForDeclaration.
|
||||
Assert(lhs.type === 'ForDeclaration');
|
||||
// iii. Let iterationEnv be NewDeclarativeEnvironment(oldEnv).
|
||||
iterationEnv = new DeclarativeEnvironmentRecord(oldEnv);
|
||||
// iv. Perform BindingInstantiation for lhs passing iterationEnv as the argument.
|
||||
BindingInstantiation(lhs, iterationEnv);
|
||||
// v. Set the running execution context's LexicalEnvironment to iterationEnv.
|
||||
surroundingAgent.runningExecutionContext.LexicalEnvironment = iterationEnv;
|
||||
// vi. If destructuring is false, then
|
||||
if (destructuring === false) {
|
||||
// 1. Assert: lhs binds a single name.
|
||||
// 2. Let lhsName be the sole element of BoundNames of lhs.
|
||||
const lhsName = BoundNames(lhs)[0];
|
||||
// 3. Let lhsRef be ! ResolveBinding(lhsName).
|
||||
lhsRef = X(ResolveBinding(lhsName, undefined, lhs.strict));
|
||||
}
|
||||
}
|
||||
let status: PlainCompletion<unknown>;
|
||||
// i. If destructuring is false, then
|
||||
if (destructuring === false) {
|
||||
// i. If lhsRef is an abrupt completion, then
|
||||
if (lhsRef instanceof AbruptCompletion) {
|
||||
// 1. Let status be lhsRef.
|
||||
status = lhsRef;
|
||||
} else if (lhsKind === 'lexicalBinding') { // ii. Else is lhsKind is lexicalBinding, then
|
||||
// 1. Let status be InitializeReferencedBinding(lhsRef, nextValue).
|
||||
status = yield* InitializeReferencedBinding(Q(lhsRef) as ReferenceRecord, nextValue);
|
||||
} else { // iii. Else,
|
||||
status = yield* PutValue(Q(lhsRef) as ReferenceRecord, nextValue);
|
||||
}
|
||||
} else { // j. Else,
|
||||
// i. If lhsKind is assignment, then
|
||||
if (lhsKind === 'assignment') {
|
||||
// 1. Let status be DestructuringAssignmentEvaluation of assignmentPattern with argument nextValue.
|
||||
status = yield* DestructuringAssignmentEvaluation(assignmentPattern as ParseNode.ObjectAssignmentPattern | ParseNode.ArrayAssignmentPattern, nextValue);
|
||||
} else if (lhsKind === 'varBinding') { // ii. Else if lhsKind is varBinding, then
|
||||
// 1. Assert: lhs is a ForBinding.
|
||||
Assert(lhs.type === 'ForBinding');
|
||||
// 2. Let status be BindingInitialization of lhs with arguments nextValue and undefined.
|
||||
status = yield* BindingInitialization(lhs, nextValue, Value.undefined);
|
||||
} else { // iii. Else,
|
||||
// 1. Assert: lhsKind is lexicalBinding.
|
||||
Assert(lhsKind === 'lexicalBinding');
|
||||
// 2. Assert: lhs is a ForDeclaration.
|
||||
Assert(lhs.type === 'ForDeclaration');
|
||||
// 3. Let status be BindingInitialization of lhs with arguments nextValue and iterationEnv.
|
||||
status = yield* BindingInitialization(lhs, nextValue, iterationEnv!);
|
||||
}
|
||||
}
|
||||
// k. If status is an abrupt completion, then
|
||||
if (status instanceof AbruptCompletion) {
|
||||
// i. Set the running execution context's LexicalEnvironment to oldEnv.
|
||||
surroundingAgent.runningExecutionContext.LexicalEnvironment = oldEnv;
|
||||
// ii. if iterationKind is enumerate, then
|
||||
if (iterationKind === 'enumerate') {
|
||||
// 1. Return status.
|
||||
return status as Completion<Value | void>;
|
||||
} else { // iv. Else,
|
||||
// 1. Assert: iterationKind is iterate.
|
||||
Assert(iterationKind === 'iterate');
|
||||
// 2. If iteratorKind is async, return ? AsyncIteratorClose(iteratorRecord, status).
|
||||
if (iteratorKind === 'async') {
|
||||
return Q(yield* AsyncIteratorClose(iteratorRecord, status)) as Completion<Value | void>;
|
||||
}
|
||||
// 3 .Return ? IteratorClose(iteratorRecord, status).
|
||||
return Q(yield* IteratorClose(iteratorRecord, EnsureCompletion(status)));
|
||||
}
|
||||
}
|
||||
// l. Let result be the result of evaluating stmt.
|
||||
const result = EnsureCompletion(yield* Evaluate(stmt));
|
||||
// m. Set the running execution context's LexicalEnvironment to oldEnv.
|
||||
surroundingAgent.runningExecutionContext.LexicalEnvironment = oldEnv;
|
||||
// n. If LoopContinues(result, labelSet) is false, then
|
||||
if (LoopContinues(result, labelSet) === Value.false) {
|
||||
// Set _status_ to Completion(UpdateEmpty(_result_, _V_)).
|
||||
status = UpdateEmpty(result, V);
|
||||
// i. If iterationKind is enumerate, then
|
||||
if (iterationKind === 'enumerate') {
|
||||
// 1. Return ? _status_.
|
||||
return Q(status as Completion<Value | void>);
|
||||
} else { // ii. Else,
|
||||
// 1. Assert: iterationKind is iterate.
|
||||
Assert(iterationKind === 'iterate');
|
||||
// 2. If iteratorKind is async, return ? AsyncIteratorClose(iteratorRecord, status).
|
||||
if (iteratorKind === 'async') {
|
||||
return Q(yield* AsyncIteratorClose(iteratorRecord, status)) as Completion<Value | void>;
|
||||
}
|
||||
// 3. Return ? IteratorClose(iteratorRecord, status).
|
||||
return Q(yield* IteratorClose(iteratorRecord, EnsureCompletion(status)));
|
||||
}
|
||||
}
|
||||
// o. If result.[[Value]] is not empty, set V to result.[[Value]].
|
||||
if (result.Value !== undefined) {
|
||||
V = result.Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-runtime-semantics-bindinginstantiation */
|
||||
// ForDeclaration : LetOrConst ForBinding
|
||||
function BindingInstantiation({ LetOrConst, ForBinding }: ParseNode.ForDeclaration, environment: DeclarativeEnvironmentRecord) {
|
||||
// 1. Assert: environment is a declarative Environment Record.
|
||||
Assert(environment instanceof DeclarativeEnvironmentRecord);
|
||||
// 2. For each element name of the BoundNames of ForBinding, do
|
||||
for (const name of BoundNames(ForBinding)) {
|
||||
// a. If IsConstantDeclaration of LetOrConst is true, then
|
||||
if (IsConstantDeclaration(LetOrConst)) {
|
||||
// i. Perform ! environment.CreateImmutableBinding(name, true).
|
||||
X(environment.CreateImmutableBinding(name, Value.true));
|
||||
} else { // b. Else,
|
||||
// i. Perform ! environment.CreateMutableBinding(name, false).
|
||||
X(environment.CreateMutableBinding(name, Value.false));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-for-in-and-for-of-statements-runtime-semantics-evaluation */
|
||||
// ForBinding : BindingIdentifier
|
||||
export function Evaluate_ForBinding({ BindingIdentifier, strict }: ParseNode.ForBinding) {
|
||||
// 1. Let bindingId be StringValue of BindingIdentifier.
|
||||
const bindingId = StringValue(BindingIdentifier!);
|
||||
// 2. Return ? ResolveBinding(bindingId).
|
||||
return ResolveBinding(bindingId, undefined, strict);
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
import { JSStringSet } from '../helpers.mts';
|
||||
import type { ParseNode } from '../parser/ParseNode.mts';
|
||||
import { LabelledEvaluation } from './all.mts';
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-labelled-statements-runtime-semantics-evaluation */
|
||||
export function Evaluate_LabelledStatement(LabelledStatement: ParseNode.LabelledStatement) {
|
||||
// 1. Let newLabelSet be a new empty List.
|
||||
const newLabelSet = new JSStringSet();
|
||||
// 2. Return LabelledEvaluation of this LabelledStatement with argument newLabelSet.
|
||||
return LabelledEvaluation(LabelledStatement, newLabelSet);
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
import { Evaluate, type PlainEvaluator } from '../evaluator.mts';
|
||||
import {
|
||||
Q, X,
|
||||
} from '../completion.mts';
|
||||
import { Value } from '../value.mts';
|
||||
import { surroundingAgent } from '../host-defined/engine.mts';
|
||||
import { IsAnonymousFunctionDefinition, StringValue, type FunctionDeclaration } from '../static-semantics/all.mts';
|
||||
import { OutOfRange } from '../helpers.mts';
|
||||
import type { ParseNode } from '../parser/ParseNode.mts';
|
||||
import { NamedEvaluation, BindingInitialization } from './all.mts';
|
||||
import {
|
||||
GetValue,
|
||||
InitializeReferencedBinding,
|
||||
ResolveBinding,
|
||||
} from '#self';
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-let-and-const-declarations-runtime-semantics-evaluation */
|
||||
// LexicalBinding :
|
||||
// BindingIdentifier
|
||||
// BindingIdentifier Initializer
|
||||
function* Evaluate_LexicalBinding_BindingIdentifier({ BindingIdentifier, Initializer, strict }: ParseNode.LexicalBinding): PlainEvaluator {
|
||||
if (Initializer) {
|
||||
// 1. Let bindingId be StringValue of BindingIdentifier.
|
||||
const bindingId = StringValue(BindingIdentifier!);
|
||||
// 2. Let lhs be ResolveBinding(bindingId).
|
||||
const lhs = X(ResolveBinding(bindingId, undefined, strict));
|
||||
let value: Value;
|
||||
// 3. If IsAnonymousFunctionDefinition(Initializer) is true, then
|
||||
if (IsAnonymousFunctionDefinition(Initializer)) {
|
||||
// a. Let value be NamedEvaluation of Initializer with argument bindingId.
|
||||
value = Q(yield* NamedEvaluation(Initializer as FunctionDeclaration, bindingId));
|
||||
} else { // 4. Else,
|
||||
// a. Let rhs be the result of evaluating Initializer.
|
||||
const rhs = Q(yield* Evaluate(Initializer));
|
||||
// b. Let value be ? GetValue(rhs).
|
||||
value = Q(yield* GetValue(rhs));
|
||||
}
|
||||
// 5. Return InitializeReferencedBinding(lhs, value).
|
||||
return yield* InitializeReferencedBinding(lhs, value);
|
||||
} else {
|
||||
// 1. Let lhs be ResolveBinding(StringValue of BindingIdentifier).
|
||||
const lhs = yield* ResolveBinding(StringValue(BindingIdentifier!), undefined, strict);
|
||||
// 2. Return InitializeReferencedBinding(lhs, undefined).
|
||||
return yield* InitializeReferencedBinding(lhs, Value.undefined);
|
||||
}
|
||||
}
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-let-and-const-declarations-runtime-semantics-evaluation */
|
||||
// LexicalBinding : BindingPattern Initializer
|
||||
function* Evaluate_LexicalBinding_BindingPattern(LexicalBinding: ParseNode.LexicalBinding) {
|
||||
const { BindingPattern, Initializer } = LexicalBinding;
|
||||
const rhs = Q(yield* Evaluate(Initializer!));
|
||||
const value = Q(yield* GetValue(rhs));
|
||||
const env = surroundingAgent.runningExecutionContext.LexicalEnvironment;
|
||||
return yield* BindingInitialization(BindingPattern!, value, env);
|
||||
}
|
||||
|
||||
export function* Evaluate_LexicalBinding(LexicalBinding: ParseNode.LexicalBinding) {
|
||||
switch (true) {
|
||||
case !!LexicalBinding.BindingIdentifier:
|
||||
return yield* Evaluate_LexicalBinding_BindingIdentifier(LexicalBinding);
|
||||
case !!LexicalBinding.BindingPattern:
|
||||
return yield* Evaluate_LexicalBinding_BindingPattern(LexicalBinding);
|
||||
default:
|
||||
throw new OutOfRange('Evaluate_LexicalBinding', LexicalBinding);
|
||||
}
|
||||
}
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-let-and-const-declarations-runtime-semantics-evaluation */
|
||||
// BindingList : BindingList `,` LexicalBinding
|
||||
//
|
||||
// (implicit)
|
||||
// BindingList : LexicalBinding
|
||||
export function* Evaluate_BindingList(BindingList: ParseNode.BindingList) {
|
||||
// 1. Let next be the result of evaluating BindingList.
|
||||
// 3. Return the result of evaluating LexicalBinding.
|
||||
let next;
|
||||
for (const LexicalBinding of BindingList) {
|
||||
next = yield* Evaluate_LexicalBinding(LexicalBinding);
|
||||
Q(next);
|
||||
}
|
||||
return next;
|
||||
}
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-let-and-const-declarations-runtime-semantics-evaluation */
|
||||
// LexicalDeclaration : LetOrConst BindingList `;`
|
||||
export function* Evaluate_LexicalDeclaration({ BindingList }: ParseNode.LexicalDeclaration): PlainEvaluator {
|
||||
// 1. Let next be the result of evaluating BindingList.
|
||||
Q(yield* Evaluate_BindingList(BindingList));
|
||||
// 3. Return NormalCompletion(empty).
|
||||
return undefined;
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
import { Value } from '../value.mts';
|
||||
import { StringValue, NumericValue } from '../static-semantics/all.mts';
|
||||
import { OutOfRange } from '../helpers.mts';
|
||||
import type { ParseNode } from '../parser/ParseNode.mts';
|
||||
import { NormalCompletion } from '../completion.mts';
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-literals-runtime-semantics-evaluation */
|
||||
// Literal :
|
||||
// NullLiteral
|
||||
// BooleanLiteral
|
||||
// NumericLiteral
|
||||
// StringLiteral
|
||||
export function Evaluate_Literal(Literal: ParseNode.Literal): NormalCompletion<Value> {
|
||||
switch (Literal.type) {
|
||||
case 'NullLiteral':
|
||||
// 1. Return null.
|
||||
return NormalCompletion(Value.null);
|
||||
case 'BooleanLiteral':
|
||||
// 1. If BooleanLiteral is the token false, return false.
|
||||
if (Literal.value === false) {
|
||||
return NormalCompletion(Value.false);
|
||||
}
|
||||
// 2. If BooleanLiteral is the token true, return true.
|
||||
if (Literal.value === true) {
|
||||
return NormalCompletion(Value.true);
|
||||
}
|
||||
throw new OutOfRange('Evaluate_Literal', Literal);
|
||||
case 'NumericLiteral':
|
||||
// 1. Return the NumericValue of NumericLiteral as defined in 11.8.3.
|
||||
return NormalCompletion(NumericValue(Literal));
|
||||
case 'StringLiteral':
|
||||
return NormalCompletion(StringValue(Literal));
|
||||
default:
|
||||
throw new OutOfRange('Evaluate_Literal', Literal);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
import { Value } from '../value.mts';
|
||||
import { Evaluate, type ValueEvaluator } from '../evaluator.mts';
|
||||
import { Q, X } from '../completion.mts';
|
||||
import type { ParseNode } from '../parser/ParseNode.mts';
|
||||
import { GetValue, ToBoolean } from '#self';
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-binary-logical-operators-runtime-semantics-evaluation */
|
||||
// LogicalANDExpression :
|
||||
// LogicalANDExpression `&&` BitwiseORExpression
|
||||
export function* Evaluate_LogicalANDExpression({ LogicalANDExpression, BitwiseORExpression }: ParseNode.LogicalANDExpression): ValueEvaluator {
|
||||
// 1. Let lref be the result of evaluating LogicalANDExpression.
|
||||
const lref = Q(yield* Evaluate(LogicalANDExpression));
|
||||
// 2. Let lval be ? GetValue(lref).
|
||||
const lval = Q(yield* GetValue(lref));
|
||||
// 3. Let lbool be ! ToBoolean(lval).
|
||||
const lbool = X(ToBoolean(lval));
|
||||
// 4. If lbool is false, return lval.
|
||||
if (lbool === Value.false) {
|
||||
return lval;
|
||||
}
|
||||
// 5. Let rref be the result of evaluating BitwiseORExpression.
|
||||
const rref = Q(yield* Evaluate(BitwiseORExpression));
|
||||
// 6. Return ? GetValue(rref).
|
||||
return Q(yield* GetValue(rref));
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
import { Value } from '../value.mts';
|
||||
import { Evaluate, type ValueEvaluator } from '../evaluator.mts';
|
||||
import { Q, X } from '../completion.mts';
|
||||
import type { ParseNode } from '../parser/ParseNode.mts';
|
||||
import { GetValue, ToBoolean } from '#self';
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-binary-logical-operators-runtime-semantics-evaluation */
|
||||
// LogicalORExpression :
|
||||
// LogicalORExpression `||` LogicalANDExpression
|
||||
export function* Evaluate_LogicalORExpression({ LogicalORExpression, LogicalANDExpression }: ParseNode.LogicalORExpression): ValueEvaluator {
|
||||
// 1. Let lref be the result of evaluating LogicalORExpression.
|
||||
const lref = Q(yield* Evaluate(LogicalORExpression));
|
||||
// 2. Let lval be ? GetValue(lref).
|
||||
const lval = Q(yield* GetValue(lref));
|
||||
// 3. Let lbool be ! ToBoolean(lval).
|
||||
const lbool = X(ToBoolean(lval));
|
||||
// 4. If lbool is false, return lval.
|
||||
if (lbool === Value.true) {
|
||||
return lval;
|
||||
}
|
||||
// 5. Let rref be the result of evaluating LogicalANDExpression.
|
||||
const rref = Q(yield* Evaluate(LogicalANDExpression));
|
||||
// 6. Return ? GetValue(rref).
|
||||
return Q(yield* GetValue(rref));
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
import { F } from '#self';
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-runtime-semantics-mv-s */
|
||||
// StringNumericLiteral :::
|
||||
// [empty]
|
||||
// StrWhiteSpace
|
||||
// StrWhiteSpace_opt StrNumericLiteral StrWhiteSpace_opt
|
||||
export function MV_StringNumericLiteral(StringNumericLiteral: string) {
|
||||
return F(Number(StringNumericLiteral));
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
import { Evaluate } from '../evaluator.mts';
|
||||
import { Q, X } from '../completion.mts';
|
||||
import { OutOfRange } from '../helpers.mts';
|
||||
import { StringValue } from '../static-semantics/all.mts';
|
||||
import type { ParseNode } from '../parser/ParseNode.mts';
|
||||
import {
|
||||
EvaluatePropertyAccessWithExpressionKey,
|
||||
EvaluatePropertyAccessWithIdentifierKey,
|
||||
} from './all.mts';
|
||||
import { GetValue, MakePrivateReference } from '#self';
|
||||
import type { PlainEvaluator, ReferenceRecord } from '#self';
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-property-accessors-runtime-semantics-evaluation */
|
||||
// MemberExpression : MemberExpression `[` Expression `]`
|
||||
// CallExpression : CallExpression `[` Expression `]`
|
||||
function* Evaluate_MemberExpression_Expression({ strict, MemberExpression, Expression }: ParseNode.MemberExpression): PlainEvaluator<ReferenceRecord> {
|
||||
// 1. Let baseReference be the result of evaluating |MemberExpression|.
|
||||
const baseReference = Q(yield* Evaluate(MemberExpression));
|
||||
// 2. Let baseValue be ? GetValue(baseReference).
|
||||
const baseValue = Q(yield* GetValue(baseReference));
|
||||
// 3. If the code matched by this |MemberExpression| is strict mode code, let strict be true; else let strict be false.
|
||||
// 4. Return ? EvaluatePropertyAccessWithExpressionKey(baseValue, |Expression|, strict).
|
||||
return Q(yield* EvaluatePropertyAccessWithExpressionKey(baseValue, Expression!, strict));
|
||||
}
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-property-accessors-runtime-semantics-evaluation */
|
||||
// MemberExpression : MemberExpression `.` IdentifierName
|
||||
// CallExpression : CallExpression `.` IdentifierName
|
||||
function* Evaluate_MemberExpression_IdentifierName({ strict, MemberExpression, IdentifierName }: ParseNode.MemberExpression): PlainEvaluator<ReferenceRecord> {
|
||||
// 1. Let baseReference be the result of evaluating |MemberExpression|.
|
||||
const baseReference = Q(yield* Evaluate(MemberExpression));
|
||||
// 2. Let baseValue be ? GetValue(baseReference).
|
||||
const baseValue = Q(yield* GetValue(baseReference));
|
||||
// 3. If the code matched by this |MemberExpression| is strict mode code, let strict be true; else let strict be false.
|
||||
// 4. Return ! EvaluatePropertyAccessWithIdentifierKey(baseValue, |IdentifierName|, strict).
|
||||
return X(EvaluatePropertyAccessWithIdentifierKey(baseValue, IdentifierName!, strict));
|
||||
}
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-property-accessors-runtime-semantics-evaluation */
|
||||
// MemberExpression : MemberExpression `.` PrivateIdentifier
|
||||
// CallExpression : CallExpression `.` PrivateIdentifier
|
||||
function* Evaluate_MemberExpression_PrivateIdentifier({ MemberExpression, PrivateIdentifier }: ParseNode.MemberExpression): PlainEvaluator<ReferenceRecord> {
|
||||
// 1. Let baseReference be the result of evaluating MemberExpression.
|
||||
const baseReference = Q(yield* Evaluate(MemberExpression));
|
||||
// 2. Let baseValue be ? GetValue(baseReference).
|
||||
const baseValue = Q(yield* GetValue(baseReference));
|
||||
// 3. Let fieldNameString be the StringValue of PrivateIdentifier.
|
||||
const fieldNameString = StringValue(PrivateIdentifier!);
|
||||
// 4. Return ! MakePrivateReference(bv, fieldNameString).
|
||||
return X(MakePrivateReference(baseValue, fieldNameString));
|
||||
}
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-property-accessors-runtime-semantics-evaluation */
|
||||
// MemberExpression :
|
||||
// MemberExpression `[` Expression `]`
|
||||
// MemberExpression `.` IdentifierName
|
||||
// CallExpression :
|
||||
// CallExpression `[` Expression `]`
|
||||
// CallExpression `.` IdentifierName
|
||||
export function Evaluate_MemberExpression(MemberExpression: ParseNode.MemberExpression) {
|
||||
switch (true) {
|
||||
case !!MemberExpression.Expression:
|
||||
return Evaluate_MemberExpression_Expression(MemberExpression);
|
||||
case !!MemberExpression.IdentifierName:
|
||||
return Evaluate_MemberExpression_IdentifierName(MemberExpression);
|
||||
case !!MemberExpression.PrivateIdentifier:
|
||||
return Evaluate_MemberExpression_PrivateIdentifier(MemberExpression);
|
||||
default:
|
||||
throw new OutOfRange('Evaluate_MemberExpression', MemberExpression);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,356 @@
|
||||
import { surroundingAgent } from '../host-defined/engine.mts';
|
||||
import {
|
||||
Value, Descriptor, PrivateName, UndefinedValue, type PropertyKeyValue, ObjectValue, BooleanValue,
|
||||
} from '../value.mts';
|
||||
import {
|
||||
Q, X,
|
||||
} from '../completion.mts';
|
||||
import { OutOfRange } from '../helpers.mts';
|
||||
import type { ParseNode } from '../parser/ParseNode.mts';
|
||||
import type { PlainEvaluator } from '../evaluator.mts';
|
||||
import { ClassElementDefinitionRecord, DefineMethod, Evaluate_PropertyName } from './all.mts';
|
||||
import {
|
||||
OrdinaryObjectCreate,
|
||||
OrdinaryFunctionCreate,
|
||||
DefinePropertyOrThrow,
|
||||
SetFunctionName,
|
||||
MakeMethod,
|
||||
sourceTextMatchedBy,
|
||||
type FunctionObject,
|
||||
} from '#self';
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-privateelement-specification-type */
|
||||
export interface PrivateElementRecord_Value {
|
||||
readonly Key: PrivateName;
|
||||
readonly Kind: 'method' | 'field';
|
||||
Value?: Value;
|
||||
readonly Get?: undefined;
|
||||
readonly Set?: undefined;
|
||||
}
|
||||
export interface PrivateElementRecord_Accessor {
|
||||
readonly Key: PrivateName;
|
||||
readonly Kind: 'accessor';
|
||||
Value?: Value;
|
||||
readonly Get?: FunctionObject | UndefinedValue;
|
||||
readonly Set?: FunctionObject | UndefinedValue;
|
||||
}
|
||||
export type PrivateElementRecord = PrivateElementRecord_Value | PrivateElementRecord_Accessor;
|
||||
export const PrivateElementRecord = function PrivateElementRecord(value: PrivateElementRecord) {
|
||||
Object.setPrototypeOf(value, PrivateElementRecord.prototype);
|
||||
return value;
|
||||
} as {
|
||||
(value: PrivateElementRecord): PrivateElementRecord;
|
||||
[Symbol.hasInstance](instance: unknown): instance is PrivateElementRecord;
|
||||
};
|
||||
|
||||
// -decorator
|
||||
// +decorator: remove this function
|
||||
/** https://tc39.es/ecma262/#sec-definemethodproperty */
|
||||
function* DefineMethodProperty(key: PropertyKeyValue | PrivateName, homeObject: ObjectValue, closure: FunctionObject, enumerable: BooleanValue): PlainEvaluator<PrivateElementRecord | undefined> {
|
||||
// 1. If key is a Private Name, then
|
||||
if (key instanceof PrivateName) {
|
||||
// a. Return PrivateElement { [[Key]]: key, [[Kind]]: method, [[Value]]: closure }.
|
||||
return PrivateElementRecord({
|
||||
Key: key,
|
||||
Kind: 'method',
|
||||
Value: closure,
|
||||
});
|
||||
} else { // 2. Else,
|
||||
// a. Let desc be the PropertyDescriptor { [[Value]]: closure, [[Writable]]: true, [[Enumerable]]: enumerable, [[Configurable]]: true }.
|
||||
const desc = Descriptor({
|
||||
Value: closure,
|
||||
Writable: Value.true,
|
||||
Enumerable: enumerable,
|
||||
Configurable: Value.true,
|
||||
});
|
||||
// b. Perform ? DefinePropertyOrThrow(homeObject, key, desc).
|
||||
Q(yield* DefinePropertyOrThrow(homeObject, key, desc));
|
||||
// c. Return empty.
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
// MethodDefinition :
|
||||
// ClassElementName `(` UniqueFormalParameters `)` `{` FunctionBody `}`
|
||||
// `get` ClassElementName `(` `)` `{` FunctionBody `}`
|
||||
// `set` ClassElementName `(` PropertySetParameterList `)` `{` FunctionBody `}`
|
||||
// -decorator signature
|
||||
function MethodDefinitionEvaluation_MethodDefinition(MethodDefinition: ParseNode.MethodDefinition, object: ObjectValue, enumerable: BooleanValue): PlainEvaluator<ClassElementDefinitionRecord>
|
||||
// +decorator signature
|
||||
function MethodDefinitionEvaluation_MethodDefinition(MethodDefinition: ParseNode.MethodDefinition, object: ObjectValue): PlainEvaluator<ClassElementDefinitionRecord>
|
||||
function* MethodDefinitionEvaluation_MethodDefinition(MethodDefinition: ParseNode.MethodDefinition, object: ObjectValue, enumerable?: BooleanValue): PlainEvaluator<ClassElementDefinitionRecord | PrivateElementRecord | void> {
|
||||
switch (true) {
|
||||
case !!MethodDefinition.UniqueFormalParameters: {
|
||||
// 1. Let methodDef be ? DefineMethod of MethodDefinition with argument object.
|
||||
const methodDef = Q(yield* DefineMethod(MethodDefinition, object));
|
||||
// 2. Perform ! SetFunctionName(methodDef.[[Closure]], methodDef.[[Key]]).
|
||||
X(SetFunctionName(methodDef.Closure, methodDef.Key));
|
||||
// 3. Return ? DefineMethodProperty(methodDef.[[Key]], object, methodDef.[[Closure]], enumerable).
|
||||
if (enumerable) {
|
||||
return Q(yield* DefineMethodProperty(methodDef.Key, object, methodDef.Closure, enumerable));
|
||||
} else {
|
||||
return ClassElementDefinitionRecord({
|
||||
Key: methodDef.Key,
|
||||
Kind: 'method',
|
||||
Value: methodDef.Closure,
|
||||
Decorators: undefined,
|
||||
});
|
||||
}
|
||||
}
|
||||
case !!MethodDefinition.PropertySetParameterList: {
|
||||
const { ClassElementName, PropertySetParameterList, FunctionBody } = MethodDefinition;
|
||||
// 1. Let propKey be the result of evaluating ClassElementName.
|
||||
const propKey = Q(yield* Evaluate_PropertyName(ClassElementName));
|
||||
// 3. Let scope be the running execution context's LexicalEnvironment.
|
||||
const scope = surroundingAgent.runningExecutionContext.LexicalEnvironment;
|
||||
// 4. Let privateScope be the running execution context's PrivateEnvironment.
|
||||
const privateScope = surroundingAgent.runningExecutionContext.PrivateEnvironment;
|
||||
// 5. Let sourceText be the source text matched by MethodDefinition.
|
||||
const sourceText = sourceTextMatchedBy(MethodDefinition);
|
||||
// 6. Let closure be OrdinaryFunctionCreate(%Function.prototype%, sourceText, PropertySetParameterList, FunctionBody, non-lexical-this, scope, privateScope).
|
||||
const closure = OrdinaryFunctionCreate(surroundingAgent.intrinsic('%Function.prototype%'), sourceText, PropertySetParameterList, FunctionBody, 'non-lexical-this', scope, privateScope);
|
||||
// 7. Perform MakeMethod(closure, object).
|
||||
MakeMethod(closure, object);
|
||||
// 8. Perform SetFunctionName(closure, propKey, "get").
|
||||
SetFunctionName(closure, propKey, Value('set'));
|
||||
if (enumerable) {
|
||||
// 9. If propKey is a Private Name, then
|
||||
if (propKey instanceof PrivateName) {
|
||||
// a. Return PrivateElement { [[Key]]: propKey, [[Kind]]: accessor, [[Get]]: undefined, [[Set]]: closure }.
|
||||
return PrivateElementRecord({
|
||||
Key: propKey,
|
||||
Kind: 'accessor',
|
||||
Get: Value.undefined,
|
||||
Set: closure,
|
||||
});
|
||||
} else { // 10. Else,
|
||||
// a. Let desc be the PropertyDescriptor { [[Get]]: closure, [[Enumerable]]: enumerable, [[Configurable]]: true }.
|
||||
const desc = Descriptor({
|
||||
Set: closure,
|
||||
Enumerable: enumerable,
|
||||
Configurable: Value.true,
|
||||
});
|
||||
// b. Perform ? DefinePropertyOrThrow(object, propKey, desc).
|
||||
Q(yield* DefinePropertyOrThrow(object, propKey, desc));
|
||||
// c. Return empty.
|
||||
return undefined;
|
||||
}
|
||||
} else {
|
||||
return ClassElementDefinitionRecord({
|
||||
Key: propKey,
|
||||
Kind: 'setter',
|
||||
Set: closure,
|
||||
Decorators: undefined,
|
||||
});
|
||||
}
|
||||
}
|
||||
case !MethodDefinition.UniqueFormalParameters && !MethodDefinition.PropertySetParameterList: {
|
||||
const { ClassElementName, FunctionBody } = MethodDefinition;
|
||||
// 1. Let propKey be the result of evaluating ClassElementName.
|
||||
const propKey = Q(yield* Evaluate_PropertyName(ClassElementName));
|
||||
// 3. Let scope be the running execution context's LexicalEnvironment.
|
||||
const scope = surroundingAgent.runningExecutionContext.LexicalEnvironment;
|
||||
// 4. Let privateScope be the running execution context's PrivateEnvironment.
|
||||
const privateScope = surroundingAgent.runningExecutionContext.PrivateEnvironment;
|
||||
// 5. Let formalParameterList be an instance of the production FormalParameters : [empty].
|
||||
const formalParameterList: ParseNode.FormalParameters = [];
|
||||
// 6. Let sourceText be the source text matched by MethodDefinition.
|
||||
const sourceText = sourceTextMatchedBy(MethodDefinition);
|
||||
// 7. Let closure be OrdinaryFunctionCreate(%Function.prototype%, sourceText, formalParameterList, FunctionBody, non-lexical-this, scope, privateScope).
|
||||
const closure = OrdinaryFunctionCreate(surroundingAgent.intrinsic('%Function.prototype%'), sourceText, formalParameterList, FunctionBody, 'non-lexical-this', scope, privateScope);
|
||||
// 8. Perform MakeMethod(closure, object).
|
||||
MakeMethod(closure, object);
|
||||
// 9. Perform SetFunctionName(closure, propKey, "get").
|
||||
SetFunctionName(closure, propKey, Value('get'));
|
||||
if (enumerable) {
|
||||
// 10. If propKey is a Private Name, then
|
||||
if (propKey instanceof PrivateName) {
|
||||
return PrivateElementRecord({
|
||||
Key: propKey,
|
||||
Kind: 'accessor',
|
||||
Get: closure,
|
||||
Set: Value.undefined,
|
||||
});
|
||||
} else { // 11. Else,
|
||||
// a. Let desc be the PropertyDescriptor { [[Get]]: closure, [[Enumerable]]: enumerable, [[Configurable]]: true }.
|
||||
const desc = Descriptor({
|
||||
Get: closure,
|
||||
Enumerable: enumerable,
|
||||
Configurable: Value.true,
|
||||
});
|
||||
// b. Perform ? DefinePropertyOrThrow(object, propKey, desc).
|
||||
Q(yield* DefinePropertyOrThrow(object, propKey, desc));
|
||||
// c. Return empty.
|
||||
return undefined;
|
||||
}
|
||||
} else {
|
||||
return ClassElementDefinitionRecord({
|
||||
Key: propKey,
|
||||
Kind: 'getter',
|
||||
Get: closure,
|
||||
Decorators: undefined,
|
||||
});
|
||||
}
|
||||
}
|
||||
default:
|
||||
throw new OutOfRange('MethodDefinitionEvaluation_MethodDefinition', MethodDefinition);
|
||||
}
|
||||
}
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-async-function-definitions-MethodDefinitionEvaluation */
|
||||
// AsyncMethod :
|
||||
// `async` ClassElementName `(` UniqueFormalParameters `)` `{` AsyncBody `}`
|
||||
// -decorator signature
|
||||
function MethodDefinitionEvaluation_AsyncMethod(AsyncMethod: ParseNode.AsyncMethod, object: ObjectValue, enumerable: BooleanValue): PlainEvaluator<PrivateElementRecord | void>
|
||||
// +decorator signature
|
||||
function MethodDefinitionEvaluation_AsyncMethod(AsyncMethod: ParseNode.AsyncMethod, object: ObjectValue): PlainEvaluator<ClassElementDefinitionRecord>
|
||||
function* MethodDefinitionEvaluation_AsyncMethod(AsyncMethod: ParseNode.AsyncMethod, object: ObjectValue, enumerable?: BooleanValue): PlainEvaluator<ClassElementDefinitionRecord | PrivateElementRecord | void> {
|
||||
const { ClassElementName, UniqueFormalParameters, AsyncBody } = AsyncMethod;
|
||||
// 1. Let propKey be the result of evaluating ClassElementName.
|
||||
const propKey = Q(yield* Evaluate_PropertyName(ClassElementName));
|
||||
// 3. Let scope be the LexicalEnvironment of the running execution context.
|
||||
const scope = surroundingAgent.runningExecutionContext.LexicalEnvironment;
|
||||
// 4. Let privateScope be the running execution context's PrivateEnvironment.
|
||||
const privateScope = surroundingAgent.runningExecutionContext.PrivateEnvironment;
|
||||
// 5. Let sourceText be the source text matched by AsyncMethod.
|
||||
const sourceText = sourceTextMatchedBy(AsyncMethod);
|
||||
// 6. Let closure be ! OrdinaryFunctionCreate(%AsyncFunction.prototype%, sourceText, UniqueFormalParameters, AsyncBody, non-lexical-this, scope, privateScope).
|
||||
const closure = X(OrdinaryFunctionCreate(surroundingAgent.intrinsic('%AsyncFunction.prototype%'), sourceText, UniqueFormalParameters, AsyncBody, 'non-lexical-this', scope, privateScope));
|
||||
// 7. Perform ! MakeMethod(closure, object).
|
||||
X(MakeMethod(closure, object));
|
||||
// 8. Perform ! SetFunctionName(closure, propKey).
|
||||
X(SetFunctionName(closure, propKey));
|
||||
if (enumerable) {
|
||||
// 9. Return ? DefineMethodProperty(propKey, object, closure, enumerable).
|
||||
return Q(yield* DefineMethodProperty(propKey, object, closure, enumerable));
|
||||
} else {
|
||||
return ClassElementDefinitionRecord({
|
||||
Key: propKey,
|
||||
Kind: 'method',
|
||||
Value: closure,
|
||||
Decorators: undefined,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-generator-function-definitions-runtime-semantics-propertydefinitionevaluation */
|
||||
// GeneratorMethod :
|
||||
// `*` ClassElementName `(` UniqueFormalParameters `)` `{` GeneratorBody `}`
|
||||
function MethodDefinitionEvaluation_GeneratorMethod(GeneratorMethod: ParseNode.GeneratorMethod, object: ObjectValue, enumerable: BooleanValue): PlainEvaluator<PrivateElementRecord | void>
|
||||
function MethodDefinitionEvaluation_GeneratorMethod(GeneratorMethod: ParseNode.GeneratorMethod, object: ObjectValue): PlainEvaluator<ClassElementDefinitionRecord>
|
||||
function* MethodDefinitionEvaluation_GeneratorMethod(GeneratorMethod: ParseNode.GeneratorMethod, object: ObjectValue, enumerable?: BooleanValue): PlainEvaluator<ClassElementDefinitionRecord | PrivateElementRecord | void> {
|
||||
const { ClassElementName, UniqueFormalParameters, GeneratorBody } = GeneratorMethod;
|
||||
// 1. Let propKey be the result of evaluating ClassElementName.
|
||||
let propKey = yield* Evaluate_PropertyName(ClassElementName);
|
||||
propKey = Q(propKey);
|
||||
// 3. Let scope be the LexicalEnvironment of the running execution context.
|
||||
const scope = surroundingAgent.runningExecutionContext.LexicalEnvironment;
|
||||
// 4. Let privateScope be the running execution context's PrivateEnvironment.
|
||||
const privateScope = surroundingAgent.runningExecutionContext.PrivateEnvironment;
|
||||
// 5. Let sourceText be the source text matched by GeneratorMethod.
|
||||
const sourceText = sourceTextMatchedBy(GeneratorMethod);
|
||||
// 6. Let closure be ! OrdinaryFunctionCreate(%GeneratorFunction.prototype%, sourceText, UniqueFormalParameters, AsyncBody, non-lexical-this, scope, privateScope).
|
||||
const closure = X(OrdinaryFunctionCreate(surroundingAgent.intrinsic('%GeneratorFunction.prototype%'), sourceText, UniqueFormalParameters, GeneratorBody, 'non-lexical-this', scope, privateScope));
|
||||
// 7. Perform ! MakeMethod(closure, object).
|
||||
X(MakeMethod(closure, object));
|
||||
// 8. Perform ! SetFunctionName(closure, propKey).
|
||||
X(SetFunctionName(closure, propKey));
|
||||
// 9. Let prototype be OrdinaryObjectCreate(%GeneratorFunction.prototype.prototype%).
|
||||
const prototype = OrdinaryObjectCreate(surroundingAgent.intrinsic('%GeneratorFunction.prototype.prototype%'));
|
||||
// 10. Perform DefinePropertyOrThrow(closure, "prototype", PropertyDescriptor { [[Value]]: prototype, [[Writable]]: true, [[Enumerable]]: false, [[Configurable]]: false }).
|
||||
X(DefinePropertyOrThrow(closure, Value('prototype'), Descriptor({
|
||||
Value: prototype,
|
||||
Writable: Value.true,
|
||||
Enumerable: Value.false,
|
||||
Configurable: Value.false,
|
||||
})));
|
||||
if (enumerable) {
|
||||
// 11. Return ? DefineMethodProperty(propKey, object, closure, enumerable).
|
||||
return Q(yield* DefineMethodProperty(propKey, object, closure, enumerable));
|
||||
} else {
|
||||
return ClassElementDefinitionRecord({
|
||||
Key: propKey,
|
||||
Kind: 'method',
|
||||
Value: closure,
|
||||
Decorators: undefined,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-asyncgenerator-definitions-propertydefinitionevaluation */
|
||||
// AsyncGeneratorMethod :
|
||||
// `async` `*` PropertyName `(` UniqueFormalParameters `)` `{` AsyncGeneratorBody `}`
|
||||
function MethodDefinitionEvaluation_AsyncGeneratorMethod(AsyncGeneratorMethod: ParseNode.AsyncGeneratorMethod, object: ObjectValue, enumerable: BooleanValue): PlainEvaluator<PrivateElementRecord | void>
|
||||
function MethodDefinitionEvaluation_AsyncGeneratorMethod(AsyncGeneratorMethod: ParseNode.AsyncGeneratorMethod, object: ObjectValue): PlainEvaluator<ClassElementDefinitionRecord>
|
||||
function* MethodDefinitionEvaluation_AsyncGeneratorMethod(AsyncGeneratorMethod: ParseNode.AsyncGeneratorMethod, object: ObjectValue, enumerable?: BooleanValue): PlainEvaluator<ClassElementDefinitionRecord | PrivateElementRecord | void> {
|
||||
const { ClassElementName, UniqueFormalParameters, AsyncGeneratorBody } = AsyncGeneratorMethod;
|
||||
// 1. Let propKey be the result of evaluating ClassElementName.
|
||||
let propKey = yield* Evaluate_PropertyName(ClassElementName);
|
||||
propKey = Q(propKey);
|
||||
// 3. Let scope be the LexicalEnvironment of the running execution context.
|
||||
const scope = surroundingAgent.runningExecutionContext.LexicalEnvironment;
|
||||
// 4. Let privateScope be the running execution context's PrivateEnvironment.
|
||||
const privateEnv = surroundingAgent.runningExecutionContext.PrivateEnvironment;
|
||||
// 5. Let sourceText be the source text matched by AsyncGeneratorMethod.
|
||||
const sourceText = sourceTextMatchedBy(AsyncGeneratorMethod);
|
||||
// 6. Let closure be ! OrdinaryFunctionCreate(%AsyncGeneratorFunction.prototype%, sourceText, UniqueFormalParameters, AsyncGeneratorBody, non-lexical-this, scope, privateScope).
|
||||
const closure = X(OrdinaryFunctionCreate(surroundingAgent.intrinsic('%AsyncGeneratorFunction.prototype%'), sourceText, UniqueFormalParameters, AsyncGeneratorBody, 'non-lexical-this', scope, privateEnv));
|
||||
// 7. Perform ! MakeMethod(closure, object).
|
||||
X(MakeMethod(closure, object));
|
||||
// 9. Perform ! SetFunctionName(closure, propKey).
|
||||
X(SetFunctionName(closure, propKey));
|
||||
// 9. Let prototype be OrdinaryObjectCreate(%AsyncGeneratorFunction.prototype.prototype%).
|
||||
const prototype = OrdinaryObjectCreate(surroundingAgent.intrinsic('%AsyncGeneratorFunction.prototype.prototype%'));
|
||||
// 10. Perform DefinePropertyOrThrow(closure, "prototype", PropertyDescriptor { [[Value]]: prototype, [[Writable]]: true, [[Enumerable]]: false, [[Configurable]]: false }).
|
||||
X(DefinePropertyOrThrow(closure, Value('prototype'), Descriptor({
|
||||
Value: prototype,
|
||||
Writable: Value.true,
|
||||
Enumerable: Value.false,
|
||||
Configurable: Value.false,
|
||||
})));
|
||||
if (enumerable) {
|
||||
// 11. Return ? DefineMethodProperty(propKey, object, closure, enumerable).
|
||||
return Q(yield* DefineMethodProperty(propKey, object, closure, enumerable));
|
||||
} else {
|
||||
return ClassElementDefinitionRecord({
|
||||
Key: propKey,
|
||||
Kind: 'method',
|
||||
Value: closure,
|
||||
Decorators: undefined,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// -decorator
|
||||
export function MethodDefinitionEvaluation(node: ParseNode.MethodDefinitionLike, object: ObjectValue, enumerable: BooleanValue): PlainEvaluator<PrivateElementRecord | void>
|
||||
// +decorator
|
||||
export function MethodDefinitionEvaluation(node: ParseNode.MethodDefinitionLike, object: ObjectValue): PlainEvaluator<ClassElementDefinitionRecord>
|
||||
export function MethodDefinitionEvaluation(node: ParseNode.MethodDefinitionLike, object: ObjectValue, enumerable?: BooleanValue): PlainEvaluator<ClassElementDefinitionRecord | PrivateElementRecord | void> {
|
||||
if (enumerable) {
|
||||
switch (node.type) {
|
||||
case 'MethodDefinition':
|
||||
return MethodDefinitionEvaluation_MethodDefinition(node, object, enumerable);
|
||||
case 'AsyncMethod':
|
||||
return MethodDefinitionEvaluation_AsyncMethod(node, object, enumerable);
|
||||
case 'GeneratorMethod':
|
||||
return MethodDefinitionEvaluation_GeneratorMethod(node, object, enumerable);
|
||||
case 'AsyncGeneratorMethod':
|
||||
return MethodDefinitionEvaluation_AsyncGeneratorMethod(node, object, enumerable);
|
||||
default:
|
||||
throw new OutOfRange('MethodDefinitionEvaluation', node);
|
||||
}
|
||||
} else {
|
||||
switch (node.type) {
|
||||
case 'MethodDefinition':
|
||||
return MethodDefinitionEvaluation_MethodDefinition(node, object);
|
||||
case 'AsyncMethod':
|
||||
return MethodDefinitionEvaluation_AsyncMethod(node, object);
|
||||
case 'GeneratorMethod':
|
||||
return MethodDefinitionEvaluation_GeneratorMethod(node, object);
|
||||
case 'AsyncGeneratorMethod':
|
||||
return MethodDefinitionEvaluation_AsyncGeneratorMethod(node, object);
|
||||
default:
|
||||
throw new OutOfRange('MethodDefinitionEvaluation', node);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
import { Value } from '../value.mts';
|
||||
import { NormalCompletion } from '../completion.mts';
|
||||
import { Evaluate } from '../evaluator.mts';
|
||||
import type { ParseNode } from '../parser/ParseNode.mts';
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-module-semantics-runtime-semantics-evaluation */
|
||||
// Module :
|
||||
// [empty]
|
||||
// ModuleBody
|
||||
export function* Evaluate_Module({ ModuleBody }: ParseNode.Module) {
|
||||
if (!ModuleBody) {
|
||||
return NormalCompletion(Value.undefined);
|
||||
}
|
||||
return yield* Evaluate(ModuleBody);
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
import type { ParseNode } from '../parser/ParseNode.mts';
|
||||
import { Evaluate_StatementList } from './all.mts';
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-module-semantics-runtime-semantics-evaluation */
|
||||
// ModuleBody : ModuleItemList
|
||||
export function Evaluate_ModuleBody({ ModuleItemList }: ParseNode.ModuleBody) {
|
||||
// TODO(ts): ModuleItemList might contain ImportDeclaration or ExportDeclaration which is not accepted by Evaluate_StatementList.
|
||||
// @ts-expect-error
|
||||
return Evaluate_StatementList(ModuleItemList);
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
import { Q } from '../completion.mts';
|
||||
import type { ValueEvaluator } from '../evaluator.mts';
|
||||
import type { ParseNode } from '../parser/ParseNode.mts';
|
||||
import { EvaluateStringOrNumericBinaryExpression } from './all.mts';
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-multiplicative-operators-runtime-semantics-evaluation */
|
||||
// MultiplicativeExpression :
|
||||
// MultiplicativeExpression MultiplicativeOperator ExponentiationExpression
|
||||
export function* Evaluate_MultiplicativeExpression({
|
||||
MultiplicativeExpression,
|
||||
MultiplicativeOperator,
|
||||
ExponentiationExpression,
|
||||
}: ParseNode.MultiplicativeExpression): ValueEvaluator {
|
||||
// 1. Let opText be the source text matched by MultiplicativeOperator.
|
||||
const opText = MultiplicativeOperator;
|
||||
// 2. Return ? EvaluateStringOrNumericBinaryExpression(MultiplicativeExpression, opText, ExponentiationExpression).
|
||||
return Q(yield* EvaluateStringOrNumericBinaryExpression(MultiplicativeExpression, opText, ExponentiationExpression));
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
import { Value } from '../value.mts';
|
||||
import { Q } from '../completion.mts';
|
||||
import { OutOfRange } from '../helpers.mts';
|
||||
import type { ParseNode } from '../parser/ParseNode.mts';
|
||||
import type { ValueEvaluator } from '../evaluator.mts';
|
||||
import {
|
||||
ClassDefinitionEvaluation,
|
||||
InstantiateOrdinaryFunctionExpression,
|
||||
InstantiateAsyncFunctionExpression,
|
||||
InstantiateGeneratorFunctionExpression,
|
||||
InstantiateAsyncGeneratorFunctionExpression,
|
||||
InstantiateArrowFunctionExpression,
|
||||
InstantiateAsyncArrowFunctionExpression,
|
||||
DecoratorListEvaluation,
|
||||
} from './all.mts';
|
||||
import type {
|
||||
FunctionDeclaration, FunctionObject, PrivateName, PropertyKeyValue,
|
||||
} from '#self';
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-function-definitions-runtime-semantics-namedevaluation */
|
||||
// FunctionExpression :
|
||||
// `function` `(` FormalParameters `)` `{` FunctionBody `}`
|
||||
function NamedEvaluation_FunctionExpression(FunctionExpression: ParseNode.FunctionExpression, name: PropertyKeyValue | PrivateName) {
|
||||
return InstantiateOrdinaryFunctionExpression(FunctionExpression, name);
|
||||
}
|
||||
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-generator-function-definitions-runtime-semantics-namedevaluation */
|
||||
// GeneratorExpression :
|
||||
// `function` `*` `(` FormalParameters `)` `{` GeneratorBody `}`
|
||||
function NamedEvaluation_GeneratorExpression(GeneratorExpression: ParseNode.GeneratorExpression, name: PropertyKeyValue | PrivateName) {
|
||||
return InstantiateGeneratorFunctionExpression(GeneratorExpression, name);
|
||||
}
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-async-function-definitions-runtime-semantics-namedevaluation */
|
||||
// AsyncFunctionExpression :
|
||||
// `async` `function` `(` FormalParameters `)` `{` AsyncBody `}`
|
||||
function NamedEvaluation_AsyncFunctionExpression(AsyncFunctionExpression: ParseNode.AsyncFunctionExpression, name: PropertyKeyValue | PrivateName) {
|
||||
return InstantiateAsyncFunctionExpression(AsyncFunctionExpression, name);
|
||||
}
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-asyncgenerator-definitions-namedevaluation */
|
||||
// AsyncGeneratorExpression :
|
||||
// `async` `function` `*` `(` FormalParameters `)` `{` AsyncGeneratorBody `}`
|
||||
function NamedEvaluation_AsyncGeneratorExpression(AsyncGeneratorExpression: ParseNode.AsyncGeneratorExpression, name: PropertyKeyValue | PrivateName) {
|
||||
return InstantiateAsyncGeneratorFunctionExpression(AsyncGeneratorExpression, name);
|
||||
}
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-arrow-function-definitions-runtime-semantics-namedevaluation */
|
||||
// ArrowFunction :
|
||||
// ArrowParameters `=>` ConciseBody
|
||||
function NamedEvaluation_ArrowFunction(ArrowFunction: ParseNode.ArrowFunction, name: PropertyKeyValue | PrivateName) {
|
||||
return InstantiateArrowFunctionExpression(ArrowFunction, name);
|
||||
}
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-arrow-function-definitions-runtime-semantics-namedevaluation */
|
||||
// AsyncArrowFunction :
|
||||
// ArrowParameters `=>` AsyncConciseBody
|
||||
function NamedEvaluation_AsyncArrowFunction(AsyncArrowFunction: ParseNode.AsyncArrowFunction, name: PropertyKeyValue | PrivateName) {
|
||||
return InstantiateAsyncArrowFunctionExpression(AsyncArrowFunction, name);
|
||||
}
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-class-definitions-runtime-semantics-namedevaluation */
|
||||
// ClassExpression : `class` ClassTail
|
||||
function* NamedEvaluation_ClassExpression(ClassExpression: ParseNode.ClassExpression, name: PropertyKeyValue | PrivateName) {
|
||||
const { ClassTail, Decorators } = ClassExpression;
|
||||
const decorators = Decorators ? Q(yield* DecoratorListEvaluation(Decorators)) : [];
|
||||
const sourceText = ClassExpression.sourceText;
|
||||
// 1. Let value be the result of ClassDefinitionEvaluation of ClassTail with arguments undefined and name.
|
||||
const value = yield* ClassDefinitionEvaluation(ClassTail, Value.undefined, name, sourceText, decorators);
|
||||
Q(value);
|
||||
// 4. Return value.
|
||||
return value;
|
||||
}
|
||||
|
||||
export function* NamedEvaluation(F: FunctionDeclaration, name: PropertyKeyValue | PrivateName): ValueEvaluator<FunctionObject> {
|
||||
switch (F.type) {
|
||||
case 'FunctionExpression':
|
||||
return NamedEvaluation_FunctionExpression(F, name);
|
||||
case 'GeneratorExpression':
|
||||
return NamedEvaluation_GeneratorExpression(F, name);
|
||||
case 'AsyncFunctionExpression':
|
||||
return NamedEvaluation_AsyncFunctionExpression(F, name);
|
||||
case 'AsyncGeneratorExpression':
|
||||
return NamedEvaluation_AsyncGeneratorExpression(F, name);
|
||||
case 'ArrowFunction':
|
||||
return NamedEvaluation_ArrowFunction(F, name);
|
||||
case 'AsyncArrowFunction':
|
||||
return NamedEvaluation_AsyncArrowFunction(F, name);
|
||||
case 'ClassExpression':
|
||||
return yield* NamedEvaluation_ClassExpression(F, name);
|
||||
case 'ParenthesizedExpression':
|
||||
return yield* NamedEvaluation(F.Expression, name);
|
||||
default:
|
||||
throw new OutOfRange('NamedEvaluation', F);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
import { surroundingAgent } from '../host-defined/engine.mts';
|
||||
import { Evaluate, type ValueEvaluator } from '../evaluator.mts';
|
||||
import { Q } from '../completion.mts';
|
||||
import type { ParseNode } from '../parser/ParseNode.mts';
|
||||
import { ArgumentListEvaluation } from './all.mts';
|
||||
import {
|
||||
Assert,
|
||||
Construct,
|
||||
GetValue,
|
||||
IsConstructor,
|
||||
} from '#self';
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-evaluatenew */
|
||||
function* EvaluateNew(constructExpr: ParseNode.LeftHandSideExpression, args: undefined | ParseNode.Arguments) {
|
||||
// 1. Assert: constructExpr is either a NewExpression or a MemberExpression.
|
||||
// 2. Assert: arguments is either empty or an Arguments.
|
||||
Assert(args === undefined || Array.isArray(args));
|
||||
// 3. Let ref be the result of evaluating constructExpr.
|
||||
const ref = Q(yield* Evaluate(constructExpr));
|
||||
// 4. Let constructor be ? GetValue(ref).
|
||||
const constructor = Q(yield* GetValue(ref));
|
||||
let argList;
|
||||
// 5. If arguments is empty, let argList be a new empty List.
|
||||
if (args === undefined) {
|
||||
argList = [];
|
||||
} else { // 6. Else,
|
||||
// a. Let argList be ? ArgumentListEvaluation of arguments.
|
||||
argList = Q(yield* ArgumentListEvaluation(args));
|
||||
}
|
||||
// 7. If IsConstructor(constructor) is false, throw a TypeError exception.
|
||||
if (!IsConstructor(constructor)) {
|
||||
return surroundingAgent.Throw('TypeError', 'NotAConstructor', constructor);
|
||||
}
|
||||
// 8. Return ? Construct(constructor, argList).
|
||||
return Q(yield* Construct(constructor, argList));
|
||||
}
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-new-operator-runtime-semantics-evaluation */
|
||||
// NewExpression :
|
||||
// `new` NewExpression
|
||||
// `new` MemberExpression Arguments
|
||||
export function* Evaluate_NewExpression({ MemberExpression, Arguments }: ParseNode.NewExpression): ValueEvaluator {
|
||||
if (!Arguments) {
|
||||
// 1. Return ? EvaluateNew(NewExpression, empty).
|
||||
return Q(yield* EvaluateNew(MemberExpression, undefined));
|
||||
} else {
|
||||
// 1. Return ? EvaluateNew(MemberExpression, Arguments).
|
||||
return Q(yield* EvaluateNew(MemberExpression, Arguments));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
import { GetNewTarget } from '#self';
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-meta-properties-runtime-semantics-evaluation */
|
||||
// NewTarget : `new` `.` `target`
|
||||
export function Evaluate_NewTarget() {
|
||||
// 1. Return GetNewTarget().
|
||||
return GetNewTarget();
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
import { surroundingAgent } from '../host-defined/engine.mts';
|
||||
import { Value, NumberValue } from '../value.mts';
|
||||
import {
|
||||
Assert, IsIntegralNumber, Z, R,
|
||||
} from '#self';
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-numbertobigint */
|
||||
export function NumberToBigInt(number: NumberValue) {
|
||||
// 1. Assert: Type(number) is Number.
|
||||
Assert(number instanceof NumberValue);
|
||||
// 2. If IsIntegralNumber(number) is false, throw a RangeError exception.
|
||||
if (IsIntegralNumber(number) === Value.false) {
|
||||
return surroundingAgent.Throw('RangeError', 'CannotConvertDecimalToBigInt', number);
|
||||
}
|
||||
// 3. Return the BigInt value that represents the mathematical value of number.
|
||||
return Z(BigInt(R(number)));
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
import { surroundingAgent } from '../host-defined/engine.mts';
|
||||
import { Value } from '../value.mts';
|
||||
import { Q } from '../completion.mts';
|
||||
import type { ParseNode } from '../parser/ParseNode.mts';
|
||||
import type { ValueEvaluator } from '../evaluator.mts';
|
||||
import {
|
||||
PropertyDefinitionEvaluation_PropertyDefinitionList,
|
||||
} from './all.mts';
|
||||
import { OrdinaryObjectCreate } from '#self';
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-object-initializer-runtime-semantics-evaluation */
|
||||
// ObjectLiteral :
|
||||
// `{` `}`
|
||||
// `{` PropertyDefinitionList `}`
|
||||
// `{` PropertyDefinitionList `,` `}`
|
||||
export function* Evaluate_ObjectLiteral({ PropertyDefinitionList }: ParseNode.ObjectLiteral): ValueEvaluator {
|
||||
// 1. Let obj be OrdinaryObjectCreate(%Object.prototype%).
|
||||
const obj = OrdinaryObjectCreate(surroundingAgent.intrinsic('%Object.prototype%'));
|
||||
if (PropertyDefinitionList.length === 0) {
|
||||
return obj;
|
||||
}
|
||||
// 2. Perform ? PropertyDefinitionEvaluation of PropertyDefinitionList with arguments obj and true.
|
||||
Q(yield* PropertyDefinitionEvaluation_PropertyDefinitionList(PropertyDefinitionList, obj, Value.true));
|
||||
// 3. Return obj.
|
||||
return obj;
|
||||
}
|
||||
@@ -0,0 +1,128 @@
|
||||
import { ReferenceRecord, Value } from '../value.mts';
|
||||
import { Evaluate, type ExpressionEvaluator } from '../evaluator.mts';
|
||||
import { Q, X } from '../completion.mts';
|
||||
import { IsInTailPosition, StringValue } from '../static-semantics/all.mts';
|
||||
import { OutOfRange } from '../helpers.mts';
|
||||
import type { ParseNode } from '../parser/ParseNode.mts';
|
||||
import {
|
||||
EvaluateCall,
|
||||
EvaluatePropertyAccessWithExpressionKey,
|
||||
EvaluatePropertyAccessWithIdentifierKey,
|
||||
} from './all.mts';
|
||||
import { GetValue, MakePrivateReference } from '#self';
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-optional-chaining-evaluation */
|
||||
// OptionalExpression :
|
||||
// MemberExpression OptionalChain
|
||||
// CallExpression OptionalChain
|
||||
// OptionalExpression OptionalChain
|
||||
export function* Evaluate_OptionalExpression({ MemberExpression, OptionalChain }: ParseNode.OptionalExpression) {
|
||||
// 1. Let baseReference be the result of evaluating MemberExpression.
|
||||
const baseReference = Q(yield* Evaluate(MemberExpression));
|
||||
// 2. Let baseValue be ? GetValue(baseReference).
|
||||
const baseValue = Q(yield* GetValue(baseReference));
|
||||
// 3. If baseValue is undefined or null, then
|
||||
if (baseValue === Value.undefined || baseValue === Value.null) {
|
||||
// a. Return undefined.
|
||||
return Value.undefined;
|
||||
}
|
||||
// 4. Return the result of performing ChainEvaluation of OptionalChain with arguments baseValue and baseReference.
|
||||
return yield* ChainEvaluation(OptionalChain, baseValue, X(baseReference));
|
||||
}
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-optional-chaining-chain-evaluation */
|
||||
// OptionalChain :
|
||||
// `?.` Arguments
|
||||
// `?.` `[` Expression `]`
|
||||
// `?.` IdentifierName
|
||||
// `?.` PrivateIdentifier
|
||||
// OptionalChain Arguments
|
||||
// OptionalChain `[` Expression `]`
|
||||
// OptionalChain `.` IdentifierName
|
||||
// OptionalChain `.` PrivateIdentifier
|
||||
function* ChainEvaluation(node: ParseNode.OptionalChain, baseValue: Value, baseReference: Value | ReferenceRecord): ExpressionEvaluator {
|
||||
const {
|
||||
OptionalChain,
|
||||
Arguments,
|
||||
Expression,
|
||||
IdentifierName,
|
||||
PrivateIdentifier,
|
||||
} = node;
|
||||
if (Arguments) {
|
||||
if (OptionalChain) {
|
||||
// 1. Let optionalChain be OptionalChain.
|
||||
const optionalChain = OptionalChain;
|
||||
// 2. Let newReference be ? ChainEvaluation of optionalChain with arguments baseValue and baseReference.
|
||||
const newReference = Q(yield* ChainEvaluation(optionalChain, baseValue, baseReference));
|
||||
// 3. Let newValue be ? GetValue(newReference).
|
||||
const newValue = Q(yield* GetValue(newReference));
|
||||
// 4. Let thisChain be this OptionalChain.
|
||||
const thisChain = node;
|
||||
// 5. Let tailCall be IsInTailPosition(thisChain).
|
||||
const tailCall = IsInTailPosition(thisChain);
|
||||
// 6. Return ? EvaluateCall(newValue, newReference, Arguments, tailCall).
|
||||
return Q(yield* EvaluateCall(newValue, newReference, Arguments, tailCall));
|
||||
}
|
||||
// 1. Let thisChain be this OptionalChain.
|
||||
const thisChain = node;
|
||||
// 2. Let tailCall be IsInTailPosition(thisChain).
|
||||
const tailCall = IsInTailPosition(thisChain);
|
||||
// 3. Return ? EvaluateCall(baseValue, baseReference, Arguments, tailCall).
|
||||
return Q(yield* EvaluateCall(baseValue, baseReference, Arguments, tailCall));
|
||||
}
|
||||
if (Expression) {
|
||||
if (OptionalChain) {
|
||||
// 1. Let optionalChain be OptionalChain.
|
||||
const optionalChain = OptionalChain;
|
||||
// 2. Let newReference be ? ChainEvaluation of optionalChain with arguments baseValue and baseReference.
|
||||
const newReference = Q(yield* ChainEvaluation(optionalChain, baseValue, baseReference));
|
||||
// 3. Let newValue be ? GetValue(newReference).
|
||||
const newValue = Q(yield* GetValue(newReference));
|
||||
// 4. If the code matched by this OptionalChain is strict mode code, let strict be true; else let strict be false.
|
||||
const strict = node.strict;
|
||||
// 5. Return ? EvaluatePropertyAccessWithExpressionKey(newValue, Expression, strict).
|
||||
return Q(yield* EvaluatePropertyAccessWithExpressionKey(newValue, Expression, strict));
|
||||
}
|
||||
// 1. If the code matched by this OptionalChain is strict mode code, let strict be true; else let strict be false.
|
||||
const strict = node.strict;
|
||||
// 2. Return ? EvaluatePropertyAccessWithExpressionKey(baseValue, Expression, strict).
|
||||
return Q(yield* EvaluatePropertyAccessWithExpressionKey(baseValue, Expression, strict));
|
||||
}
|
||||
if (IdentifierName) {
|
||||
if (OptionalChain) {
|
||||
// 1. Let optionalChain be OptionalChain.
|
||||
const optionalChain = OptionalChain;
|
||||
// 2. Let newReference be ? ChainEvaluation of optionalChain with arguments baseValue and baseReference.
|
||||
const newReference = Q(yield* ChainEvaluation(optionalChain, baseValue, baseReference));
|
||||
// 3. Let newValue be ? GetValue(newReference).
|
||||
const newValue = Q(yield* GetValue(newReference));
|
||||
// 4. If the code matched by this OptionalChain is strict mode code, let strict be true; else let strict be false.
|
||||
const strict = node.strict;
|
||||
// 5. Return ! EvaluatePropertyAccessWithIdentifierKey(newValue, IdentifierName, strict).
|
||||
return X(EvaluatePropertyAccessWithIdentifierKey(newValue, IdentifierName, strict));
|
||||
}
|
||||
// 1. If the code matched by this OptionalChain is strict mode code, let strict be true; else let strict be false.
|
||||
const strict = node.strict;
|
||||
// 2. Return ! EvaluatePropertyAccessWithIdentifierKey(baseValue, IdentifierName, strict).
|
||||
return X(EvaluatePropertyAccessWithIdentifierKey(baseValue, IdentifierName, strict));
|
||||
}
|
||||
if (PrivateIdentifier) {
|
||||
if (OptionalChain) {
|
||||
// 1. Let optionalChain be OptionalChain.
|
||||
const optionalChain = OptionalChain;
|
||||
// 2. Let newReference be ? ChainEvaluation of optionalChain with arguments baseValue and baseReference.
|
||||
const newReference = Q(yield* ChainEvaluation(optionalChain, baseValue, baseReference));
|
||||
// 3. Let newValue be ? GetValue(newReference).
|
||||
const newValue = Q(yield* GetValue(newReference));
|
||||
// 4. Let fieldNameString be the StringValue of PrivateIdentifier.
|
||||
const fieldNameString = StringValue(PrivateIdentifier);
|
||||
// 5. Return ! MakePrivateReference(nv, fieldNameString).
|
||||
return X(MakePrivateReference(newValue, fieldNameString));
|
||||
}
|
||||
// 1. Let fieldNameString be the StringValue of PrivateIdentifier.
|
||||
const fieldNameString = StringValue(PrivateIdentifier);
|
||||
// 2. Return ! MakePrivateReference(bv, fieldNameString).
|
||||
return X(MakePrivateReference(baseValue, fieldNameString));
|
||||
}
|
||||
throw new OutOfRange('ChainEvaluation', node);
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
import { Evaluate } from '../evaluator.mts';
|
||||
import type { ParseNode } from '../parser/ParseNode.mts';
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-grouping-operator-runtime-semantics-evaluation */
|
||||
export function* Evaluate_ParenthesizedExpression({ Expression }: ParseNode.ParenthesizedExpression) {
|
||||
// 1. Return the result of evaluating Expression. This may be of type Reference.
|
||||
return yield* Evaluate(Expression);
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
import { BoundNames } from '../static-semantics/all.mts';
|
||||
import { Q } from '../completion.mts';
|
||||
import type { ParseNode } from '../parser/ParseNode.mts';
|
||||
import { isArray } from '../helpers.mts';
|
||||
import type { PlainEvaluator } from '../evaluator.mts';
|
||||
import { Evaluate_PropertyName, KeyedBindingInitialization } from './all.mts';
|
||||
import type {
|
||||
EnvironmentRecord, PlainCompletion, PropertyKeyValue, UndefinedValue, Value,
|
||||
} from '#self';
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-destructuring-binding-patterns-runtime-semantics-propertybindinginitialization */
|
||||
// BindingPropertyList : BIndingPropertyList `,` BindingProperty
|
||||
// BindingProperty :
|
||||
// SingleNameBinding
|
||||
// PropertyName `:` BindingElement
|
||||
export function* PropertyBindingInitialization(node: ParseNode.BindingPropertyList | ParseNode.BindingPropertyLike, value: Value, environment: EnvironmentRecord | UndefinedValue): PlainEvaluator<PropertyKeyValue[]> {
|
||||
if (isArray(node)) {
|
||||
// 1. Let boundNames be ? PropertyBindingInitialization of BindingPropertyList with arguments value and environment.
|
||||
// 2. Let nextNames be ? PropertyBindingInitialization of BindingProperty with arguments value and environment.
|
||||
// 3. Append each item in nextNames to the end of boundNames.
|
||||
// 4. Return boundNames.
|
||||
const boundNames: PlainCompletion<PropertyKeyValue[]> = [];
|
||||
for (const item of node) {
|
||||
const nextNames = Q(yield* PropertyBindingInitialization(item, value, environment));
|
||||
boundNames.push(...nextNames);
|
||||
}
|
||||
return boundNames;
|
||||
}
|
||||
if ('PropertyName' in node && node.PropertyName) {
|
||||
// 1. Let P be the result of evaluating PropertyName.
|
||||
const P = yield* Evaluate_PropertyName(node.PropertyName);
|
||||
Q(P);
|
||||
// 3. Perform ? KeyedBindingInitialization of BindingElement with value, environment, and P as the arguments.
|
||||
Q(yield* KeyedBindingInitialization(node.BindingElement, value, environment, P as PropertyKeyValue));
|
||||
// 4. Return a new List containing P.
|
||||
return [P as PropertyKeyValue];
|
||||
} else {
|
||||
// 1. Let name be the string that is the only element of BoundNames of SingleNameBinding.
|
||||
const name = BoundNames(node)[0];
|
||||
// 2. Perform ? KeyedBindingInitialization for SingleNameBinding using value, environment, and name as the arguments.
|
||||
Q(yield* KeyedBindingInitialization(node as ParseNode.SingleNameBinding, value, environment, name));
|
||||
// 3. Return a new List containing name.
|
||||
return [name];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
import { surroundingAgent } from '../host-defined/engine.mts';
|
||||
import {
|
||||
Value, NullValue, ObjectValue, type PropertyKeyValue, JSStringValue, BooleanValue,
|
||||
} from '../value.mts';
|
||||
import {
|
||||
StringValue,
|
||||
IsAnonymousFunctionDefinition,
|
||||
IsComputedPropertyKey,
|
||||
type FunctionDeclaration,
|
||||
} from '../static-semantics/all.mts';
|
||||
import { Evaluate, type PlainEvaluator, type ValueEvaluator } from '../evaluator.mts';
|
||||
import {
|
||||
Q, X,
|
||||
NormalCompletion,
|
||||
} from '../completion.mts';
|
||||
import { OutOfRange, kInternal } from '../helpers.mts';
|
||||
import type { ParseNode } from '../parser/ParseNode.mts';
|
||||
import { NamedEvaluation, MethodDefinitionEvaluation, Evaluate_PropertyName } from './all.mts';
|
||||
import {
|
||||
Assert,
|
||||
GetValue,
|
||||
CreateDataPropertyOrThrow,
|
||||
CopyDataProperties,
|
||||
DefineMethodProperty,
|
||||
} from '#self';
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-object-initializer-runtime-semantics-propertydefinitionevaluation */
|
||||
// PropertyDefinitionList :
|
||||
// PropertyDefinitionList `,` PropertyDefinition
|
||||
export function* PropertyDefinitionEvaluation_PropertyDefinitionList(PropertyDefinitionList: ParseNode.PropertyDefinitionList, object: ObjectValue, enumerable: BooleanValue<true>): PlainEvaluator {
|
||||
for (const PropertyDefinition of PropertyDefinitionList) {
|
||||
Q(yield* PropertyDefinitionEvaluation_PropertyDefinition(PropertyDefinition, object, enumerable));
|
||||
}
|
||||
}
|
||||
|
||||
// PropertyDefinition :
|
||||
// `...` AssignmentExpression
|
||||
// IdentifierReference
|
||||
// PropertyName `:` AssignmentExpression
|
||||
function* PropertyDefinitionEvaluation_PropertyDefinition(PropertyDefinition: ParseNode.PropertyDefinitionLike, object: ObjectValue, enumerable: BooleanValue<true>) {
|
||||
switch (PropertyDefinition.type) {
|
||||
case 'IdentifierReference':
|
||||
return yield* PropertyDefinitionEvaluation_PropertyDefinition_IdentifierReference(PropertyDefinition, object, enumerable);
|
||||
case 'PropertyDefinition':
|
||||
break;
|
||||
case 'MethodDefinition':
|
||||
case 'GeneratorMethod':
|
||||
case 'AsyncMethod':
|
||||
case 'AsyncGeneratorMethod': {
|
||||
if (surroundingAgent.feature('decorators')) {
|
||||
const methodDefinition = Q(yield* MethodDefinitionEvaluation(PropertyDefinition, object));
|
||||
Q(yield* DefineMethodProperty(object, methodDefinition, true));
|
||||
return undefined;
|
||||
} else {
|
||||
return yield* MethodDefinitionEvaluation(PropertyDefinition, object, enumerable);
|
||||
}
|
||||
}
|
||||
default:
|
||||
throw new OutOfRange('PropertyDefinitionEvaluation_PropertyDefinition', PropertyDefinition);
|
||||
}
|
||||
// PropertyDefinition :
|
||||
// PropertyName `:` AssignmentExpression
|
||||
// `...` AssignmentExpression
|
||||
const { PropertyName, AssignmentExpression } = PropertyDefinition;
|
||||
if (!PropertyName) {
|
||||
// 1. Let exprValue be the result of evaluating AssignmentExpression.
|
||||
const exprValue = Q(yield* Evaluate(AssignmentExpression));
|
||||
// 2. Let fromValue be ? GetValue(exprValue).
|
||||
const fromValue = Q(yield* GetValue(exprValue));
|
||||
// 3. Let excludedNames be a new empty List.
|
||||
const excludedNames: PropertyKeyValue[] = [];
|
||||
// 4. Return ? CopyDataProperties(object, fromValue, excludedNames).
|
||||
return Q(yield* CopyDataProperties(object, fromValue, excludedNames));
|
||||
}
|
||||
// 1. Let propKey be the result of evaluating PropertyName.
|
||||
const propKey = Q(yield* Evaluate_PropertyName(PropertyName));
|
||||
// 3. If this PropertyDefinition is contained within a Script which is being evaluated for JSON.parse, then
|
||||
let isProtoSetter;
|
||||
if (surroundingAgent.runningExecutionContext?.HostDefined?.[kInternal]?.json) {
|
||||
isProtoSetter = false;
|
||||
} else if (!IsComputedPropertyKey(PropertyName) && (propKey as JSStringValue).stringValue() === '__proto__') { // 3. Else, If _propKey_ is the String value *"__proto__"* and if IsComputedPropertyKey(|PropertyName|) is *false*,
|
||||
// a. Let isProtoSetter be true.
|
||||
isProtoSetter = true;
|
||||
} else { // 4. Else,
|
||||
// a. Let isProtoSetter be false.
|
||||
isProtoSetter = false;
|
||||
}
|
||||
let propValue;
|
||||
// 5. If IsAnonymousFunctionDefinition(AssignmentExpression) is true and isProtoSetter is false, then
|
||||
if (IsAnonymousFunctionDefinition(AssignmentExpression) && !isProtoSetter) {
|
||||
// a. Let propValue be NamedEvaluation of AssignmentExpression with argument propKey.
|
||||
propValue = yield* NamedEvaluation(AssignmentExpression as FunctionDeclaration, propKey);
|
||||
} else { // 6. Else,
|
||||
// a. Let exprValueRef be the result of evaluating AssignmentExpression.
|
||||
const exprValueRef = Q(yield* Evaluate(AssignmentExpression));
|
||||
// b. Let propValue be ? GetValue(exprValueRef).
|
||||
propValue = Q(yield* GetValue(exprValueRef));
|
||||
}
|
||||
// 7. If isProtoSetter is true, then
|
||||
if (isProtoSetter) {
|
||||
// a. If Type(propValue) is either Object or Null, then
|
||||
if (propValue instanceof ObjectValue || propValue instanceof NullValue) {
|
||||
// i. Return object.[[SetPrototypeOf]](propValue).
|
||||
return yield* object.SetPrototypeOf(propValue);
|
||||
}
|
||||
// b. Return NormalCompletion(empty).
|
||||
return NormalCompletion(undefined);
|
||||
}
|
||||
// 8. Assert: enumerable is true.
|
||||
Assert(enumerable === Value.true);
|
||||
// 9. Assert: object is an ordinary, extensible object with no non-configurable properties.
|
||||
// 10. Return ! CreateDataPropertyOrThrow(object, propKey, propValue).
|
||||
return X(CreateDataPropertyOrThrow(object, propKey as PropertyKeyValue, X(propValue)));
|
||||
}
|
||||
|
||||
// PropertyDefinition : IdentifierReference
|
||||
function* PropertyDefinitionEvaluation_PropertyDefinition_IdentifierReference(IdentifierReference: ParseNode.IdentifierReference, object: ObjectValue, enumerable: BooleanValue<true>): ValueEvaluator {
|
||||
// 1. Let propName be StringValue of IdentifierReference.
|
||||
const propName = StringValue(IdentifierReference);
|
||||
// 2. Let exprValue be the result of evaluating IdentifierReference.
|
||||
const exprValue = Q(yield* Evaluate(IdentifierReference));
|
||||
// 3. Let propValue be ? GetValue(exprValue).
|
||||
const propValue = Q(yield* GetValue(exprValue));
|
||||
// 4. Assert: enumerable is true.
|
||||
Assert(enumerable === Value.true);
|
||||
// 5. Assert: object is an ordinary, extensible object with no non-configurable properties.
|
||||
// 6. Return ! CreateDataPropertyOrThrow(object, propName, propValue).
|
||||
return X(CreateDataPropertyOrThrow(object, propName, propValue));
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
import { surroundingAgent } from '../host-defined/engine.mts';
|
||||
import { Value } from '../value.mts';
|
||||
import { Evaluate } from '../evaluator.mts';
|
||||
import { StringValue, NumericValue } from '../static-semantics/all.mts';
|
||||
import { Q, X } from '../completion.mts';
|
||||
import type { ParseNode } from '../parser/ParseNode.mts';
|
||||
import {
|
||||
Assert,
|
||||
ToString,
|
||||
GetValue,
|
||||
ToPropertyKey,
|
||||
} from '#self';
|
||||
import type {
|
||||
PlainEvaluator, PrivateEnvironmentRecord, PrivateName, PropertyKeyValue,
|
||||
} from '#self';
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-object-initializer-runtime-semantics-evaluation */
|
||||
// PropertyName :
|
||||
// LiteralPropertyName
|
||||
// ComputedPropertyName
|
||||
// LiteralPropertyName :
|
||||
// IdentifierName
|
||||
// StringLiteral
|
||||
// NumericLiteral
|
||||
// ComputedPropertyName :
|
||||
// `[` AssignmentExpression `]`
|
||||
export function* Evaluate_PropertyName(PropertyName: ParseNode.PropertyNameLike | ParseNode.PrivateIdentifier): PlainEvaluator<PropertyKeyValue | PrivateName> {
|
||||
switch (PropertyName.type) {
|
||||
case 'IdentifierName':
|
||||
return StringValue(PropertyName);
|
||||
case 'StringLiteral':
|
||||
return Value(PropertyName.value);
|
||||
case 'NumericLiteral': {
|
||||
// 1. Let nbr be the NumericValue of NumericLiteral.
|
||||
const nbr = NumericValue(PropertyName);
|
||||
// 2. Return ! ToString(nbr).
|
||||
return X(ToString(nbr));
|
||||
}
|
||||
case 'PrivateIdentifier': {
|
||||
// 1. Let privateIdentifier be StringValue of PrivateIdentifier.
|
||||
const privateIdentifier = StringValue(PropertyName);
|
||||
// 2. Let privateEnvRec be the running execution context's PrivateEnvironment.
|
||||
const privateEnvRec = surroundingAgent.runningExecutionContext.PrivateEnvironment;
|
||||
// 3. Let names be privateEnvRec.[[Names]].
|
||||
const names = (privateEnvRec as PrivateEnvironmentRecord).Names;
|
||||
// 4. Assert: Exactly one element of names is a Private Name whose [[Description]] is privateIdentifier.
|
||||
// 5. Let privateName be the Private Name in names whose [[Description]] is privateIdentifier.
|
||||
const privateName = names.find((n) => n.Description.stringValue() === privateIdentifier.stringValue());
|
||||
Assert(!!privateName);
|
||||
// 6. Return privateName.
|
||||
return privateName;
|
||||
}
|
||||
default: {
|
||||
// 1. Let exprValue be the result of evaluating AssignmentExpression.
|
||||
const exprValue = Q(yield* Evaluate(PropertyName.ComputedPropertyName));
|
||||
// 2. Let propName be ? GetValue(exprValue).
|
||||
const propName = Q(yield* GetValue(exprValue));
|
||||
// 3. Return ? ToPropertyKey(propName).
|
||||
return Q(yield* ToPropertyKey(propName));
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,16 @@
|
||||
import { Value } from '../value.mts';
|
||||
import { BodyText, FlagText } from '../static-semantics/all.mts';
|
||||
import type { ParseNode } from '../parser/ParseNode.mts';
|
||||
import { RegExpCreate } from '#self';
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-regular-expression-literals-runtime-semantics-evaluation */
|
||||
// RegularExpressionLiteral :
|
||||
// `/` RegularExpressionBody `/` RegularExpressionFlags
|
||||
export function* Evaluate_RegularExpressionLiteral(RegularExpressionLiteral: ParseNode.RegularExpressionLiteral) {
|
||||
// 1. Let pattern be ! UTF16Encode(BodyText of RegularExpressionLiteral).
|
||||
const pattern = Value(BodyText(RegularExpressionLiteral));
|
||||
// 2. Let flags be ! UTF16Encode(FlagText of RegularExpressionLiteral).
|
||||
const flags = Value(FlagText(RegularExpressionLiteral));
|
||||
// 3. Return RegExpCreate(pattern, flags).
|
||||
return yield* RegExpCreate(pattern, flags);
|
||||
}
|
||||
@@ -0,0 +1,151 @@
|
||||
import {
|
||||
surroundingAgent,
|
||||
} from '../host-defined/engine.mts';
|
||||
import { StringValue } from '../static-semantics/all.mts';
|
||||
import {
|
||||
ObjectValue,
|
||||
Value,
|
||||
wellKnownSymbols,
|
||||
} from '../value.mts';
|
||||
import { Q, X } from '../completion.mts';
|
||||
import { Evaluate } from '../evaluator.mts';
|
||||
import { OutOfRange } from '../helpers.mts';
|
||||
import type { ParseNode } from '../parser/ParseNode.mts';
|
||||
import {
|
||||
AbstractRelationalComparison,
|
||||
Call,
|
||||
GetMethod,
|
||||
GetValue,
|
||||
HasProperty,
|
||||
IsCallable,
|
||||
OrdinaryHasInstance,
|
||||
ToBoolean,
|
||||
ToPropertyKey,
|
||||
PrivateElementFind,
|
||||
} from '#self';
|
||||
import { ResolvePrivateIdentifier, type PrivateEnvironmentRecord } from '#self';
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-instanceofoperator */
|
||||
export function* InstanceofOperator(V: Value, target: Value) {
|
||||
// 1. If Type(target) is not Object, throw a TypeError exception.
|
||||
if (!(target instanceof ObjectValue)) {
|
||||
return surroundingAgent.Throw('TypeError', 'NotAnObject', target);
|
||||
}
|
||||
// 2. Let instOfHandler be ? GetMethod(target, @@hasInstance).
|
||||
const instOfHandler = Q(yield* GetMethod(target, wellKnownSymbols.hasInstance));
|
||||
// 3. If instOfHandler is not undefined, then
|
||||
if (instOfHandler !== Value.undefined) {
|
||||
// a. Return ! ToBoolean(? Call(instOfHandler, target, « V »)).
|
||||
return X(ToBoolean(Q(yield* Call(instOfHandler, target, [V]))));
|
||||
}
|
||||
// 4. If IsCallable(target) is false, throw a TypeError exception.
|
||||
if (!IsCallable(target)) {
|
||||
return surroundingAgent.Throw('TypeError', 'NotAFunction', target);
|
||||
}
|
||||
// 5. Return ? OrdinaryHasInstance(target, V).
|
||||
return Q(yield* OrdinaryHasInstance(target, V));
|
||||
}
|
||||
|
||||
// RelationalExpression : PrivateIdentifier `in` ShiftExpression
|
||||
export function* Evaluate_RelationalExpression_PrivateIdentifier({ PrivateIdentifier, ShiftExpression }: ParseNode.RelationalExpression) {
|
||||
// 1. Let privateIdentifier be the StringValue of PrivateIdentifier.
|
||||
const privateIdentifier = StringValue(PrivateIdentifier!);
|
||||
// 2. Let rref be the result of evaluating ShiftExpression.
|
||||
const rref = Q(yield* Evaluate(ShiftExpression));
|
||||
// 3. Let rval be ? GetValue(rref).
|
||||
const rval = Q(yield* GetValue(rref));
|
||||
// 4. If Type(rval) is not Object, throw a TypeError exception.
|
||||
if (!(rval instanceof ObjectValue)) {
|
||||
return surroundingAgent.Throw('TypeError', 'NotAnObject', rval);
|
||||
}
|
||||
// 5. Let privateEnv be the running execution context's PrivateEnvironment.
|
||||
const privateEnv = surroundingAgent.runningExecutionContext.PrivateEnvironment as PrivateEnvironmentRecord;
|
||||
// 6. Let privateName be ! ResolvePrivateIdentifier(privateEnv, privateIdentifier).
|
||||
const privateName = X(ResolvePrivateIdentifier(privateEnv, privateIdentifier));
|
||||
// 7. If ! PrivateElementFind(privateName, rval) is not empty, return true.
|
||||
if (X(PrivateElementFind(privateName, rval)) !== undefined) {
|
||||
return Value.true;
|
||||
}
|
||||
// 8. Return false.
|
||||
return Value.false;
|
||||
}
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-relational-operators-runtime-semantics-evaluation */
|
||||
// RelationalExpression :
|
||||
// RelationalExpression `<` ShiftExpression
|
||||
// RelationalExpression `>` ShiftExpression
|
||||
// RelationalExpression `<=` ShiftExpression
|
||||
// RelationalExpression `>=` ShiftExpression
|
||||
// RelationalExpression `instanceof` ShiftExpression
|
||||
// RelationalExpression `in` ShiftExpression
|
||||
// PrivateIdentifier `in` ShiftExpression
|
||||
export function* Evaluate_RelationalExpression(expr: ParseNode.RelationalExpression) {
|
||||
if (expr.PrivateIdentifier) {
|
||||
return yield* Evaluate_RelationalExpression_PrivateIdentifier(expr);
|
||||
}
|
||||
|
||||
const { RelationalExpression, operator, ShiftExpression } = expr;
|
||||
|
||||
// 1. Let lref be the result of evaluating RelationalExpression.
|
||||
const lref = Q(yield* Evaluate(RelationalExpression!));
|
||||
// 2. Let lval be ? GetValue(lref).
|
||||
const lval = Q(yield* GetValue(lref));
|
||||
// 3. Let rref be the result of evaluating ShiftExpression.
|
||||
const rref = Q(yield* Evaluate(ShiftExpression));
|
||||
// 4. Let rval be ? GetValue(rref).
|
||||
const rval = Q(yield* GetValue(rref));
|
||||
switch (operator) {
|
||||
case '<': {
|
||||
// 5. Let r be the result of performing Abstract Relational Comparison lval < rval.
|
||||
const r = yield* AbstractRelationalComparison(lval, rval);
|
||||
Q(r);
|
||||
// 7. If r is undefined, return false. Otherwise, return r.
|
||||
if (r === Value.undefined) {
|
||||
return Value.false;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
case '>': {
|
||||
// 5. Let r be the result of performing Abstract Relational Comparison rval < lval with LeftFirst equal to false.
|
||||
const r = yield* AbstractRelationalComparison(rval, lval, false);
|
||||
Q(r);
|
||||
// 7. If r is undefined, return false. Otherwise, return r.
|
||||
if (r === Value.undefined) {
|
||||
return Value.false;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
case '<=': {
|
||||
// 5. Let r be the result of performing Abstract Relational Comparison rval < lval with LeftFirst equal to false.
|
||||
const r = yield* AbstractRelationalComparison(rval, lval, false);
|
||||
Q(r);
|
||||
// 7. If r is true or undefined, return false. Otherwise, return true.
|
||||
if (r === Value.true || r === Value.undefined) {
|
||||
return Value.false;
|
||||
}
|
||||
return Value.true;
|
||||
}
|
||||
case '>=': {
|
||||
// 5. Let r be the result of performing Abstract Relational Comparison lval < rval.
|
||||
const r = yield* AbstractRelationalComparison(lval, rval);
|
||||
Q(r);
|
||||
// 7. If r is true or undefined, return false. Otherwise, return true.
|
||||
if (r === Value.true || r === Value.undefined) {
|
||||
return Value.false;
|
||||
}
|
||||
return Value.true;
|
||||
}
|
||||
case 'instanceof':
|
||||
// 5. Return ? InstanceofOperator(lval, rval).
|
||||
return Q(yield* InstanceofOperator(lval, rval));
|
||||
case 'in':
|
||||
// 5. Return ? InstanceofOperator(lval, rval).
|
||||
if (!(rval instanceof ObjectValue)) {
|
||||
return surroundingAgent.Throw('TypeError', 'NotAnObject', rval);
|
||||
}
|
||||
// 6. Return ? HasProperty(rval, ? ToPropertyKey(lval)).
|
||||
return Q(yield* HasProperty(rval, Q(yield* ToPropertyKey(lval))));
|
||||
default:
|
||||
throw new OutOfRange('Evaluate_RelationalExpression', operator);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
import { Value } from '../value.mts';
|
||||
import { surroundingAgent } from '../host-defined/engine.mts';
|
||||
import { StringValue } from '../static-semantics/all.mts';
|
||||
import { Q } from '../completion.mts';
|
||||
import type { ParseNode } from '../parser/ParseNode.mts';
|
||||
import {
|
||||
CopyDataProperties,
|
||||
InitializeReferencedBinding,
|
||||
OrdinaryObjectCreate,
|
||||
PutValue,
|
||||
ResolveBinding,
|
||||
} from '#self';
|
||||
import type { EnvironmentRecord, PropertyKeyValue, UndefinedValue } from '#self';
|
||||
|
||||
// BindingRestProperty : `...` BindingIdentifier
|
||||
export function* RestBindingInitialization({ BindingIdentifier }: ParseNode.BindingRestProperty, value: Value, environment: EnvironmentRecord | UndefinedValue, excludedNames: readonly PropertyKeyValue[]) {
|
||||
// 1. Let lhs be ? ResolveBinding(StringValue of BindingIdentifier, environment).
|
||||
const lhs = Q(yield* ResolveBinding(StringValue(BindingIdentifier), environment, BindingIdentifier.strict));
|
||||
// 2. Let restObj be OrdinaryObjectCreate(%Object.prototype%).
|
||||
const restObj = OrdinaryObjectCreate(surroundingAgent.intrinsic('%Object.prototype%'));
|
||||
// 3. Perform ? CopyDataProperties(restObj, value, excludedNames).
|
||||
Q(yield* CopyDataProperties(restObj, value, excludedNames));
|
||||
// 4. If environment is undefined, return PutValue(lhs, restObj).
|
||||
if (environment === Value.undefined) {
|
||||
return yield* PutValue(lhs, restObj);
|
||||
}
|
||||
// 5. Return InitializeReferencedBinding(lhs, restObj).
|
||||
return yield* InitializeReferencedBinding(lhs, restObj);
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
import { Value } from '../value.mts';
|
||||
import { Evaluate, type Evaluator } from '../evaluator.mts';
|
||||
import {
|
||||
Completion,
|
||||
Await,
|
||||
Q, X,
|
||||
ReturnCompletion,
|
||||
ThrowCompletion,
|
||||
} from '../completion.mts';
|
||||
import type { ParseNode } from '../parser/ParseNode.mts';
|
||||
import { GetValue, GetGeneratorKind } from '#self';
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-return-statement-runtime-semantics-evaluation */
|
||||
// ReturnStatement :
|
||||
// `return` `;`
|
||||
// `return` Expression `;`
|
||||
export function* Evaluate_ReturnStatement({ Expression }: ParseNode.ReturnStatement): Evaluator<ReturnCompletion | ThrowCompletion> {
|
||||
if (!Expression) {
|
||||
// 1. Return Completion { [[Type]]: return, [[Value]]: undefined, [[Target]]: empty }.
|
||||
return new Completion({ Type: 'return', Value: Value.undefined, Target: undefined });
|
||||
}
|
||||
// 1. Let exprRef be the result of evaluating Expression.
|
||||
const exprRef = Q(yield* Evaluate(Expression));
|
||||
// 1. Let exprValue be ? GetValue(exprRef).
|
||||
let exprValue = Q(yield* GetValue(exprRef));
|
||||
// 1. If ! GetGeneratorKind() is async, set exprValue to ? Await(exprValue).
|
||||
if (X(GetGeneratorKind()) === 'async') {
|
||||
exprValue = Q(yield* Await(exprValue));
|
||||
}
|
||||
// 1. Return Completion { [[Type]]: return, [[Value]]: exprValue, [[Target]]: empty }.
|
||||
return new Completion({ Type: 'return', Value: exprValue, Target: undefined });
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
import { Value } from '../value.mts';
|
||||
import { NormalCompletion } from '../completion.mts';
|
||||
import { Evaluate } from '../evaluator.mts';
|
||||
import type { ParseNode } from '../parser/ParseNode.mts';
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-script-semantics-runtime-semantics-evaluation */
|
||||
// Script :
|
||||
// [empty]
|
||||
// ScriptBody
|
||||
export function* Evaluate_Script({ ScriptBody }: ParseNode.Script) {
|
||||
if (!ScriptBody) {
|
||||
return NormalCompletion(Value.undefined);
|
||||
}
|
||||
return yield* Evaluate(ScriptBody);
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
import type { ParseNode } from '../parser/ParseNode.mts';
|
||||
import { Evaluate_StatementList } from './all.mts';
|
||||
|
||||
// ScriptBody : StatementList
|
||||
export function Evaluate_ScriptBody(ScriptBody: ParseNode.ScriptBody) {
|
||||
return Evaluate_StatementList(ScriptBody.StatementList);
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
import { Q } from '../completion.mts';
|
||||
import type { ValueEvaluator } from '../evaluator.mts';
|
||||
import type { ParseNode } from '../parser/ParseNode.mts';
|
||||
import { EvaluateStringOrNumericBinaryExpression } from './all.mts';
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-left-shift-operator-runtime-semantics-evaluation */
|
||||
// ShiftExpression :
|
||||
// ShiftExpression `<<` AdditiveExpression
|
||||
/** https://tc39.es/ecma262/#sec-signed-right-shift-operator-runtime-semantics-evaluation */
|
||||
// ShiftExpression :
|
||||
// ShiftExpression `>>` AdditiveExpression
|
||||
/** https://tc39.es/ecma262/#sec-unsigned-right-shift-operator-runtime-semantics-evaluation */
|
||||
// ShiftExpression :
|
||||
// ShiftExpression `>>>` AdditiveExpression
|
||||
export function* Evaluate_ShiftExpression({ ShiftExpression, operator, AdditiveExpression }: ParseNode.ShiftExpression): ValueEvaluator {
|
||||
return Q(yield* EvaluateStringOrNumericBinaryExpression(ShiftExpression, operator, AdditiveExpression));
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
import { Evaluate } from '../evaluator.mts';
|
||||
import {
|
||||
EnsureCompletion,
|
||||
Q,
|
||||
UpdateEmpty,
|
||||
NormalCompletion,
|
||||
} from '../completion.mts';
|
||||
import type { ParseNode } from '../parser/ParseNode.mts';
|
||||
import { surroundingAgent, type Completion, type Value } from '#self';
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-block-runtime-semantics-evaluation */
|
||||
export function* Evaluate_StatementList(StatementList: ParseNode.StatementList) {
|
||||
if (StatementList.length === 0) {
|
||||
return NormalCompletion(undefined);
|
||||
}
|
||||
|
||||
let blockCompletion: Completion<void | Value> = NormalCompletion(undefined);
|
||||
|
||||
for (let index = 0; index < StatementList.length; index += 1) {
|
||||
const StatementListItem = StatementList[index];
|
||||
|
||||
if (surroundingAgent.hostDefinedOptions.onDebugger) {
|
||||
const NextStatementListItem = StatementList[index + 1];
|
||||
surroundingAgent.runningExecutionContext.callSite.setNextLocation(NextStatementListItem);
|
||||
}
|
||||
|
||||
Q(blockCompletion);
|
||||
const itemCompletion = EnsureCompletion(yield* Evaluate(StatementListItem));
|
||||
blockCompletion = UpdateEmpty(itemCompletion, blockCompletion);
|
||||
}
|
||||
|
||||
return blockCompletion;
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
import { JSStringValue } from '../value.mts';
|
||||
import { Assert, F, isNonNegativeInteger } from '#self';
|
||||
|
||||
// https://tc39.es/proposal-string-replaceall/#sec-stringindexof
|
||||
export function StringIndexOf(string: JSStringValue, searchValue: JSStringValue, fromIndex: number) {
|
||||
// 1. Assert: Type(string) is String.
|
||||
Assert(string instanceof JSStringValue);
|
||||
// 2. Assert: Type(searchValue) is String.
|
||||
Assert(searchValue instanceof JSStringValue);
|
||||
// 3. Assert: fromIndex is a non-negative integer.
|
||||
Assert(isNonNegativeInteger(fromIndex));
|
||||
const stringStr = string.stringValue();
|
||||
const searchStr = searchValue.stringValue();
|
||||
// 4. Let len be the length of string.
|
||||
const len = stringStr.length;
|
||||
// 5. If searchValue is the empty string, and fromIndex <= len, return 𝔽(fromIndex).
|
||||
if (searchStr === '' && fromIndex <= len) {
|
||||
return F(fromIndex);
|
||||
}
|
||||
// 6. Let searchLen be the length of searchValue.
|
||||
const searchLen = searchStr.length;
|
||||
// 7. If there exists any integer k such that fromIndex ≤ k ≤ len - searchLen and for all nonnegative integers j less than searchLen,
|
||||
// the code unit at index k + j within string is the same as the code unit at index j within searchValue, let pos be the smallest (closest to -∞) such integer.
|
||||
// Otherwise, let pos be -1.
|
||||
let k = fromIndex;
|
||||
let pos = -1;
|
||||
while (k + searchLen <= len) {
|
||||
let match = true;
|
||||
for (let j = 0; j < searchLen; j += 1) {
|
||||
if (searchStr[j] !== stringStr[k + j]) {
|
||||
match = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (match) {
|
||||
pos = k;
|
||||
break;
|
||||
}
|
||||
k += 1;
|
||||
}
|
||||
// 8. Return 𝔽(pos).
|
||||
return F(pos);
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
import { JSStringValue, Value } from '../value.mts';
|
||||
import { Q } from '../completion.mts';
|
||||
import type { ValueEvaluator } from '../evaluator.mts';
|
||||
import {
|
||||
Assert, ToString, ToLength, R,
|
||||
} from '#self';
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-stringpad */
|
||||
export function* StringPad(O: Value, maxLength: Value, fillString: Value, placement: 'start' | 'end'): ValueEvaluator<JSStringValue> {
|
||||
Assert(placement === 'start' || placement === 'end');
|
||||
const S = Q(yield* ToString(O));
|
||||
const intMaxLength = R(Q(yield* ToLength(maxLength)));
|
||||
const stringLength = S.stringValue().length;
|
||||
if (intMaxLength <= stringLength) {
|
||||
return S;
|
||||
}
|
||||
let filler;
|
||||
if (fillString === Value.undefined) {
|
||||
filler = ' ';
|
||||
} else {
|
||||
filler = Q(yield* ToString(fillString)).stringValue();
|
||||
}
|
||||
if (filler === '') {
|
||||
return S;
|
||||
}
|
||||
const fillLen = intMaxLength - stringLength;
|
||||
const stringFiller = filler.repeat(Math.ceil(fillLen / filler.length));
|
||||
const truncatedStringFiller = stringFiller.slice(0, fillLen);
|
||||
if (placement === 'start') {
|
||||
return Value(truncatedStringFiller + S.stringValue());
|
||||
} else {
|
||||
return Value(S.stringValue() + truncatedStringFiller);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
import { surroundingAgent } from '../host-defined/engine.mts';
|
||||
import { ObjectValue } from '../value.mts';
|
||||
import { Q, X } from '../completion.mts';
|
||||
import type { ParseNode } from '../parser/ParseNode.mts';
|
||||
import { ArgumentListEvaluation } from './all.mts';
|
||||
import {
|
||||
Assert,
|
||||
Construct,
|
||||
GetNewTarget,
|
||||
GetThisEnvironment,
|
||||
IsConstructor,
|
||||
InitializeInstanceElements,
|
||||
isECMAScriptFunctionObject,
|
||||
type FunctionObject,
|
||||
} from '#self';
|
||||
import { FunctionEnvironmentRecord } from '#self';
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-super-keyword-runtime-semantics-evaluation */
|
||||
// SuperCall : `super` Arguments
|
||||
export function* Evaluate_SuperCall({ Arguments }: ParseNode.SuperCall) {
|
||||
// 1. Let newTarget be GetNewTarget().
|
||||
const newTarget = GetNewTarget();
|
||||
// 2. Assert: Type(newTarget) is Object.
|
||||
Assert(newTarget instanceof ObjectValue);
|
||||
// 3. Let func be ! GetSuperConstructor().
|
||||
const func = X(GetSuperConstructor());
|
||||
// 4. Let argList be ? ArgumentListEvaluation of Arguments.
|
||||
const argList = Q(yield* ArgumentListEvaluation(Arguments));
|
||||
// 5. If IsConstructor(func) is false, throw a TypeError exception.
|
||||
if (!IsConstructor(func)) {
|
||||
return surroundingAgent.Throw('TypeError', 'NotAConstructor', func);
|
||||
}
|
||||
// 6. Let result be ? Construct(func, argList, newTarget).
|
||||
const result = Q(yield* Construct(func, argList, newTarget as FunctionObject));
|
||||
// 7. Let thisER be GetThisEnvironment().
|
||||
const thisER = GetThisEnvironment();
|
||||
// 8. Assert: thisER is a Function Environment Record.
|
||||
Assert(thisER instanceof FunctionEnvironmentRecord);
|
||||
// 8. Perform ? thisER.BindThisValue(result).
|
||||
Q(thisER.BindThisValue(result));
|
||||
// 9. Let F be thisER.[[FunctionObject]].
|
||||
const F = thisER.FunctionObject;
|
||||
// 10. Assert: F is an ECMAScript function object.
|
||||
Assert(isECMAScriptFunctionObject(F));
|
||||
// 11. Perform ? InitializeInstanceElements(result, F).
|
||||
Q(yield* InitializeInstanceElements(result, F));
|
||||
// 12. Return result.
|
||||
return result;
|
||||
}
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-getsuperconstructor */
|
||||
function GetSuperConstructor() {
|
||||
// 1. Let envRec be GetThisEnvironment().
|
||||
const envRec = GetThisEnvironment();
|
||||
// 2. Assert: envRec is a function Environment Record.
|
||||
Assert(envRec instanceof FunctionEnvironmentRecord);
|
||||
// 3. Let activeFunction be envRec.[[FunctionObject]].
|
||||
const activeFunction = envRec.FunctionObject;
|
||||
// 4. Assert: activeFunction is an ECMAScript function object.
|
||||
Assert(isECMAScriptFunctionObject(activeFunction));
|
||||
// 5. Let superConstructor be ! activeFunction.[[GetPrototypeOf]]().
|
||||
const superConstructor = X(activeFunction.GetPrototypeOf());
|
||||
// 6. Return superConstructor.
|
||||
return superConstructor;
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
import { Evaluate, type ExpressionEvaluator } from '../evaluator.mts';
|
||||
import {
|
||||
ReferenceRecord, Value,
|
||||
} from '../value.mts';
|
||||
import { StringValue } from '../static-semantics/all.mts';
|
||||
import { Q } from '../completion.mts';
|
||||
import type { ParseNode } from '../parser/ParseNode.mts';
|
||||
import {
|
||||
Assert,
|
||||
GetThisEnvironment,
|
||||
GetValue,
|
||||
FunctionEnvironmentRecord,
|
||||
} from '#self';
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-makesuperpropertyreference */
|
||||
function MakeSuperPropertyReference(actualThis: Value, propertyKey: Value, strict: boolean) {
|
||||
// 1. Let env be GetThisEnvironment().
|
||||
const env = GetThisEnvironment();
|
||||
// 2. Assert: env.HasSuperBinding() is true.
|
||||
Assert(env.HasSuperBinding() === Value.true);
|
||||
// 3. Assert: env is a Function Environment Record.
|
||||
Assert(env instanceof FunctionEnvironmentRecord);
|
||||
// 4. Let baseValue be ? env.GetSuperBase().
|
||||
const baseValue = Q(env.GetSuperBase());
|
||||
// 5. Return the Reference Record { [[Base]]: baseValue, [[ReferencedName]]: propertyKey, [[Strict]]: strict, [[ThisValue]]: actualThis }.
|
||||
return new ReferenceRecord({
|
||||
Base: baseValue,
|
||||
ReferencedName: propertyKey,
|
||||
Strict: strict ? Value.true : Value.false,
|
||||
ThisValue: actualThis,
|
||||
});
|
||||
}
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-super-keyword-runtime-semantics-evaluation */
|
||||
// SuperProperty :
|
||||
// `super` `[` Expression `]`
|
||||
// `super` `.` IdentifierName
|
||||
export function* Evaluate_SuperProperty({ Expression, IdentifierName, strict }: ParseNode.SuperProperty): ExpressionEvaluator {
|
||||
// 1. Let env be GetThisEnvironment().
|
||||
const env = GetThisEnvironment();
|
||||
// 2. Let actualThis be ? env.GetThisBinding().
|
||||
const actualThis = Q(env.GetThisBinding());
|
||||
if (Expression) {
|
||||
// 3. Let propertyNameReference be the result of evaluating Expression.
|
||||
const propertyNameReference = Q(yield* Evaluate(Expression));
|
||||
// 4. Let propertyNameReference be the result of evaluating Expression.
|
||||
const propertyNameValue = Q(yield* GetValue(propertyNameReference));
|
||||
// 6. If the code matched by this SuperProperty is strict mode code, let strict be true; else let strict be false.
|
||||
// 7. Return ? MakeSuperPropertyReference(actualThis, propertyKey, strict).
|
||||
return Q(MakeSuperPropertyReference(actualThis, propertyNameValue, strict));
|
||||
} else {
|
||||
// 3. Let propertyKey be StringValue of IdentifierName.
|
||||
const propertyKey = StringValue(IdentifierName!);
|
||||
// 4. const strict = SuperProperty.strict;
|
||||
// 5. Return ? MakeSuperPropertyReference(actualThis, propertyKey, strict).
|
||||
return Q(MakeSuperPropertyReference(actualThis, propertyKey, strict));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,222 @@
|
||||
import { surroundingAgent } from '../host-defined/engine.mts';
|
||||
import { Evaluate, type StatementEvaluator, type ValueEvaluator } from '../evaluator.mts';
|
||||
import {
|
||||
BooleanValue, ReferenceRecord, Value,
|
||||
} from '../value.mts';
|
||||
import {
|
||||
Completion,
|
||||
AbruptCompletion,
|
||||
NormalCompletion,
|
||||
EnsureCompletion,
|
||||
UpdateEmpty,
|
||||
Q,
|
||||
} from '../completion.mts';
|
||||
import { OutOfRange } from '../helpers.mts';
|
||||
import type { ParseNode } from '../parser/ParseNode.mts';
|
||||
import {
|
||||
BlockDeclarationInstantiation,
|
||||
Evaluate_StatementList,
|
||||
} from './all.mts';
|
||||
import {
|
||||
Assert, GetValue, IsStrictlyEqual, DeclarativeEnvironmentRecord,
|
||||
} from '#self';
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-runtime-semantics-caseclauseisselected */
|
||||
function* CaseClauseIsSelected(C: ParseNode.CaseClause, input: Value): ValueEvaluator<BooleanValue> {
|
||||
// 1. Assert: C is an instance of the production CaseClause : `case` Expression `:` StatementList?.
|
||||
Assert(C.type === 'CaseClause');
|
||||
// 2. Let exprRef be the result of evaluating the Expression of C.
|
||||
const exprRef = Q(yield* Evaluate(C.Expression));
|
||||
// 3. Let clauseSelector be ? GetValue(exprRef).
|
||||
const clauseSelector = Q(yield* GetValue(exprRef));
|
||||
// 4. Return the result of performing Strict Equality Comparison input === clauseSelector.
|
||||
return IsStrictlyEqual(input, clauseSelector);
|
||||
}
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-runtime-semantics-caseblockevaluation */
|
||||
// CaseBlock :
|
||||
// `{` `}`
|
||||
// `{` CaseClauses `}`
|
||||
// `{` CaseClauses? DefaultClause CaseClauses? `}`
|
||||
function* CaseBlockEvaluation({ CaseClauses_a, DefaultClause, CaseClauses_b }: ParseNode.CaseBlock, input: Value): StatementEvaluator {
|
||||
switch (true) {
|
||||
case !CaseClauses_a && !DefaultClause && !CaseClauses_b: {
|
||||
// 1. Return NormalCompletion(undefined).
|
||||
return NormalCompletion(Value.undefined);
|
||||
}
|
||||
case !!CaseClauses_a && !DefaultClause && !CaseClauses_b: {
|
||||
// 1. Let V be undefined.
|
||||
let V: Value = Value.undefined;
|
||||
// 2. Let A be the List of CaseClause items in CaseClauses, in source text order.
|
||||
const A = CaseClauses_a;
|
||||
// 3. Let found be false.
|
||||
let found: BooleanValue = Value.false;
|
||||
// 4. For each CaseClause C in A, do
|
||||
for (const C of A) {
|
||||
// a. If found is false, then
|
||||
if (found === Value.false) {
|
||||
// i. Set found to ? CaseClauseIsSelected(C, input).
|
||||
found = Q(yield* CaseClauseIsSelected(C, input));
|
||||
}
|
||||
// b. If found is true, them
|
||||
if (found === Value.true) {
|
||||
// i. Let R be the result of evaluating C.
|
||||
const R = EnsureCompletion(yield* Evaluate(C));
|
||||
// ii. If R.[[Value]] is not empty, set V to R.[[Value]].
|
||||
if (R.Value !== undefined) {
|
||||
V = R.Value;
|
||||
}
|
||||
// iii. If R is an abrupt completion, return Completion(UpdateEmpty(R, V)).
|
||||
if (R instanceof AbruptCompletion) {
|
||||
return Completion(UpdateEmpty(R, V));
|
||||
}
|
||||
}
|
||||
}
|
||||
// 5. Return NormalCompletion(V).
|
||||
return NormalCompletion(V);
|
||||
}
|
||||
case !!DefaultClause: {
|
||||
// 1. Let V be undefined.
|
||||
let V: Value | ReferenceRecord = Value.undefined;
|
||||
// 2. If the first CaseClauses is present, then
|
||||
let A;
|
||||
if (CaseClauses_a) {
|
||||
// a. Let A be the List of CaseClause items in the first CaseClauses, in source text order.
|
||||
A = CaseClauses_a;
|
||||
} else { // 3. Else,
|
||||
// a. Let A be « ».
|
||||
A = [];
|
||||
}
|
||||
let found: BooleanValue = Value.false;
|
||||
// 4. For each CaseClause C in A, do
|
||||
for (const C of A) {
|
||||
// a. If found is false, then
|
||||
if (found === Value.false) {
|
||||
// i. Set found to ? CaseClauseIsSelected(C, input).
|
||||
found = Q(yield* CaseClauseIsSelected(C, input));
|
||||
}
|
||||
// b. If found is true, them
|
||||
if (found === Value.true) {
|
||||
// i. Let R be the result of evaluating C.
|
||||
const R = EnsureCompletion(yield* Evaluate(C));
|
||||
// ii. If R.[[Value]] is not empty, set V to R.[[Value]].
|
||||
if (R.Value !== undefined) {
|
||||
V = R.Value;
|
||||
}
|
||||
// iii. If R is an abrupt completion, return Completion(UpdateEmpty(R, V)).
|
||||
if (R instanceof AbruptCompletion) {
|
||||
return Completion(UpdateEmpty(R, V));
|
||||
}
|
||||
}
|
||||
}
|
||||
// 6. Let foundInB be false.
|
||||
let foundInB: BooleanValue = Value.false;
|
||||
// 7. If the second CaseClauses is present, then
|
||||
let B;
|
||||
if (CaseClauses_b) {
|
||||
// a. Let B be the List of CaseClause items in the second CaseClauses, in source text order.
|
||||
B = CaseClauses_b;
|
||||
} else { // 8. Else,
|
||||
// a. Let B be « ».
|
||||
B = [];
|
||||
}
|
||||
// 9. If found is false, then
|
||||
if (found === Value.false) {
|
||||
// a. For each CaseClause C in B, do
|
||||
for (const C of B) {
|
||||
// a. If foundInB is false, then
|
||||
if (foundInB === Value.false) {
|
||||
// i. Set foundInB to ? CaseClauseIsSelected(C, input).
|
||||
foundInB = Q(yield* CaseClauseIsSelected(C, input));
|
||||
}
|
||||
// b. If foundInB is true, them
|
||||
if (foundInB === Value.true) {
|
||||
// i. Let R be the result of evaluating C.
|
||||
const R = EnsureCompletion(yield* Evaluate(C));
|
||||
// ii. If R.[[Value]] is not empty, set V to R.[[Value]].
|
||||
if (R.Value !== undefined) {
|
||||
V = R.Value;
|
||||
}
|
||||
// iii. If R is an abrupt completion, return Completion(UpdateEmpty(R, V)).
|
||||
if (R instanceof AbruptCompletion) {
|
||||
return Completion(UpdateEmpty(R, V));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// 10. If foundInB is true, return NormalCompletion(V).
|
||||
if (foundInB === Value.true) {
|
||||
return NormalCompletion(V as Value);
|
||||
}
|
||||
// 11. Let R be the result of evaluating DefaultClause.
|
||||
const R = EnsureCompletion(yield* Evaluate(DefaultClause));
|
||||
// 12. If R.[[Value]] is not empty, set V to R.[[Value]].
|
||||
if (R.Value !== undefined) {
|
||||
V = R.Value;
|
||||
}
|
||||
// 13. If R is an abrupt completion, return Completion(UpdateEmpty(R, V)).
|
||||
if (R instanceof AbruptCompletion) {
|
||||
return Completion(UpdateEmpty(R, V));
|
||||
}
|
||||
// 14. NOTE: The following is another complete iteration of the second CaseClauses.
|
||||
// 15. For each CaseClause C in B, do
|
||||
for (const C of B) {
|
||||
// a. Let R be the result of evaluating CaseClause C.
|
||||
const innerR = EnsureCompletion(yield* Evaluate(C));
|
||||
// b. If R.[[Value]] is not empty, set V to R.[[Value]].
|
||||
if (innerR.Value !== undefined) {
|
||||
V = innerR.Value;
|
||||
}
|
||||
// c. If R is an abrupt completion, return Completion(UpdateEmpty(R, V)).
|
||||
if (innerR instanceof AbruptCompletion) {
|
||||
return Completion(UpdateEmpty(innerR, V));
|
||||
}
|
||||
}
|
||||
// 16. Return NormalCompletion(V).
|
||||
//
|
||||
return NormalCompletion(V as Value);
|
||||
}
|
||||
default:
|
||||
throw new OutOfRange('CaseBlockEvaluation', '');
|
||||
}
|
||||
}
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-switch-statement-runtime-semantics-evaluation */
|
||||
// SwitchStatement :
|
||||
// `switch` `(` Expression `)` CaseBlock
|
||||
export function* Evaluate_SwitchStatement({ Expression, CaseBlock }: ParseNode.SwitchStatement): StatementEvaluator {
|
||||
// 1. Let exprRef be the result of evaluating Expression.
|
||||
const exprRef = Q(yield* Evaluate(Expression));
|
||||
// 2. Let switchValue be ? GetValue(exprRef).
|
||||
const switchValue = Q(yield* GetValue(exprRef));
|
||||
// 3. Let oldEnv be the running execution context's LexicalEnvironment.
|
||||
const oldEnv = surroundingAgent.runningExecutionContext.LexicalEnvironment;
|
||||
// 4. Let blockEnv be NewDeclarativeEnvironment(oldEnv).
|
||||
const blockEnv = new DeclarativeEnvironmentRecord(oldEnv);
|
||||
// 5. Perform BlockDeclarationInstantiation(CaseBlock, blockEnv).
|
||||
yield* BlockDeclarationInstantiation(CaseBlock, blockEnv);
|
||||
// 6. Set the running execution context's LexicalEnvironment to blockEnv.
|
||||
surroundingAgent.runningExecutionContext.LexicalEnvironment = blockEnv;
|
||||
// 7. Let R be CaseBlockEvaluation of CaseBlock with argument switchValue.
|
||||
const R = yield* CaseBlockEvaluation(CaseBlock, switchValue);
|
||||
// 8. Set the running execution context's LexicalEnvironment to oldEnv.
|
||||
surroundingAgent.runningExecutionContext.LexicalEnvironment = oldEnv;
|
||||
// 9. return R.
|
||||
return R;
|
||||
}
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-switch-statement-runtime-semantics-evaluation */
|
||||
// CaseClause :
|
||||
// `case` Expression `:`
|
||||
// `case` Expression `:` StatementList
|
||||
// DefaultClause :
|
||||
// `case` `default` `:`
|
||||
// `case` `default` `:` StatementList
|
||||
export function* Evaluate_CaseClause({ StatementList }: ParseNode.CaseClause | ParseNode.DefaultClause) {
|
||||
if (!StatementList) {
|
||||
// 1. Return NormalCompletion(empty).
|
||||
return NormalCompletion(undefined);
|
||||
}
|
||||
// 1. Return the result of evaluating StatementList.
|
||||
return yield* Evaluate_StatementList(StatementList);
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
import { Evaluate, type ValueEvaluator } from '../evaluator.mts';
|
||||
import { IsInTailPosition } from '../static-semantics/all.mts';
|
||||
import { Q } from '../completion.mts';
|
||||
import type { ParseNode } from '../parser/ParseNode.mts';
|
||||
import { EvaluateCall } from './all.mts';
|
||||
import { GetValue } from '#self';
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-tagged-templates-runtime-semantics-evaluation */
|
||||
// MemberExpression :
|
||||
// MemberExpression TemplateLiteral
|
||||
export function* Evaluate_TaggedTemplateExpression(node: ParseNode.TaggedTemplateExpression): ValueEvaluator {
|
||||
const { MemberExpression, TemplateLiteral } = node;
|
||||
// 1. Let tagRef be ? Evaluation of MemberExpression.
|
||||
const tagRef = Q(yield* Evaluate(MemberExpression));
|
||||
// 1. Let tagFunc be ? GetValue(tagRef).
|
||||
const tagFunc = Q(yield* GetValue(tagRef));
|
||||
// 1. Let thisCall be this MemberExpression.
|
||||
const thisCall = node;
|
||||
// 1. Let tailCall be IsInTailPosition(thisCall).
|
||||
const tailCall = IsInTailPosition(thisCall);
|
||||
// 1. Return ? EvaluateCall(tagFunc, tagRef, TemplateLiteral, tailCall).
|
||||
return Q(yield* EvaluateCall(tagFunc, tagRef, TemplateLiteral, tailCall));
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
import { Value } from '../value.mts';
|
||||
import { Q } from '../completion.mts';
|
||||
import { Evaluate, type ValueEvaluator } from '../evaluator.mts';
|
||||
import { TV } from '../static-semantics/all.mts';
|
||||
import type { ParseNode } from '../parser/ParseNode.mts';
|
||||
import { GetValue, ToString } from '#self';
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-template-literals-runtime-semantics-evaluation */
|
||||
// TemplateLiteral : NoSubstitutionTemplate
|
||||
// SubstitutionTemplate : TemplateHead Expression TemplateSpans
|
||||
// TemplateSpans : TemplateTail
|
||||
// TemplateSpans : TemplateMiddleList TemplateTail
|
||||
// TemplateMiddleList : TemplateMiddle Expression
|
||||
// TemplateMiddleList : TemplateMiddleList TemplateMiddle Expression
|
||||
//
|
||||
// (implicit)
|
||||
// TemplateLiteral : SubstitutionTemplate
|
||||
export function* Evaluate_TemplateLiteral({ TemplateSpanList, ExpressionList }: ParseNode.TemplateLiteral): ValueEvaluator {
|
||||
let str = '';
|
||||
for (let i = 0; i < TemplateSpanList.length - 1; i += 1) {
|
||||
const Expression = ExpressionList[i];
|
||||
const head = TV(TemplateSpanList[i]);
|
||||
// 2. Let subRef be the result of evaluating Expression.
|
||||
const subRef = Q(yield* Evaluate(Expression));
|
||||
// 3. Let sub be ? GetValue(subRef).
|
||||
const sub = Q(yield* GetValue(subRef));
|
||||
// 4. Let middle be ? ToString(sub).
|
||||
const middle = Q(yield* ToString(sub));
|
||||
str += head;
|
||||
str += middle.stringValue();
|
||||
}
|
||||
const tail = TV(TemplateSpanList[TemplateSpanList.length - 1]);
|
||||
return Value(str + tail);
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
import { Q, type ValueCompletion } from '../completion.mts';
|
||||
import type { ParseNode } from '../parser/ParseNode.mts';
|
||||
import { ResolveThisBinding } from '#self';
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-this-keyword-runtime-semantics-evaluation */
|
||||
// PrimaryExpression : `this`
|
||||
export function Evaluate_This(_PrimaryExpression: ParseNode.ThisExpression): ValueCompletion {
|
||||
return Q(ResolveThisBinding());
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
import {
|
||||
Evaluate,
|
||||
} from '../evaluator.mts';
|
||||
import {
|
||||
Q,
|
||||
ThrowCompletion,
|
||||
} from '../completion.mts';
|
||||
import type { ParseNode } from '../parser/ParseNode.mts';
|
||||
import {
|
||||
GetValue,
|
||||
} from '#self';
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-throw-statement-runtime-semantics-evaluation */
|
||||
// ThrowStatement : `throw` Expression `;`
|
||||
export function* Evaluate_ThrowStatement({ Expression }: ParseNode.ThrowStatement) {
|
||||
// 1. Let exprRef be the result of evaluating Expression.
|
||||
const exprRef = Q(yield* Evaluate(Expression));
|
||||
// 2. Let exprValue be ? GetValue(exprRef).
|
||||
const exprValue = Q(yield* GetValue(exprRef));
|
||||
// 3. Return ThrowCompletion(exprValue).
|
||||
return ThrowCompletion(exprValue);
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user