mirror of
https://github.com/facebookarchive/prepack.git
synced 2024-09-11 14:46:37 +03:00
move IteratorBindingInitialization to its own function
This commit is contained in:
parent
4ac76366e9
commit
a84e482941
@ -1196,7 +1196,6 @@ function filterFeatures(data: BannerData): boolean {
|
||||
let features = data.features;
|
||||
if (features.includes("class")) return false;
|
||||
if (features.includes("default-parameters")) return false;
|
||||
if (features.includes("destructuring-binding")) return false;
|
||||
if (features.includes("generators")) return false;
|
||||
return true;
|
||||
}
|
||||
|
@ -541,6 +541,26 @@ export function CreateDataProperty(realm: Realm, O: ObjectValue, P: PropertyKeyV
|
||||
return O.$DefineOwnProperty(P, newDesc);
|
||||
}
|
||||
|
||||
// ECMA262 7.3.5
|
||||
export function CreateMethodProperty(realm: Realm, O: ObjectValue, P: PropertyKeyValue, V: Value): boolean {
|
||||
// 1. Assert: Type(O) is Object.
|
||||
invariant(O instanceof ObjectValue, "Not an object value");
|
||||
|
||||
// 2. Assert: IsPropertyKey(P) is true.
|
||||
invariant(IsPropertyKey(realm, P), "Not a property key");
|
||||
|
||||
// 3. Let newDesc be the PropertyDescriptor{[[Value]]: V, [[Writable]]: true, [[Enumerable]]: false, [[Configurable]]: true}.
|
||||
let newDesc = {
|
||||
value: V,
|
||||
writable: true,
|
||||
enumerable: false,
|
||||
configurable: true
|
||||
};
|
||||
|
||||
// 4. Return ? O.[[DefineOwnProperty]](P, newDesc).
|
||||
return O.$DefineOwnProperty(P, newDesc);
|
||||
}
|
||||
|
||||
// ECMA262 7.3.6
|
||||
export function CreateDataPropertyOrThrow(realm: Realm, O: Value, P: PropertyKeyValue, V: Value): boolean {
|
||||
// 1. Assert: Type(O) is Object.
|
||||
|
@ -34,6 +34,7 @@ import {
|
||||
Reference,
|
||||
LexicalEnvironment
|
||||
} from "../environment.js";
|
||||
import { AbruptCompletion, ThrowCompletion } from "../completions.js";
|
||||
import {
|
||||
GetV,
|
||||
GetThisValue,
|
||||
@ -42,7 +43,17 @@ import {
|
||||
RequireObjectCoercible,
|
||||
HasSomeCompatibleType
|
||||
} from "./index.js";
|
||||
import type { BabelNode, BabelNodeVariableDeclaration, BabelNodeIdentifier, BabelNodeRestElement, BabelNodeObjectPattern, BabelNodeArrayPattern, BabelNodeStatement } from "babel-types";
|
||||
import { IteratorStep, IteratorValue } from "./iterator.js";
|
||||
import type {
|
||||
BabelNode,
|
||||
BabelNodeVariableDeclaration,
|
||||
BabelNodeIdentifier,
|
||||
BabelNodeRestElement,
|
||||
BabelNodeObjectPattern,
|
||||
BabelNodeArrayPattern,
|
||||
BabelNodeStatement,
|
||||
BabelNodeLVal,
|
||||
} from "babel-types";
|
||||
|
||||
|
||||
// ECMA262 6.2.3
|
||||
@ -488,6 +499,87 @@ export function BindingInitialization(realm: Realm, node: BabelNode, value: Valu
|
||||
throw new Error("Unknown node " + node.type);
|
||||
}
|
||||
|
||||
export function IteratorBindingInitialization(realm: Realm, formals: Array<BabelNodeLVal>, iteratorRecord: {$Iterator: ObjectValue, $Done: boolean}, strict: boolean, environment?: LexicalEnvironment) {
|
||||
for (let param of formals) {
|
||||
switch (param.type) {
|
||||
// ECMA262 13.3.3.6
|
||||
|
||||
// SingleNameBinding : BindingIdentifier Initializer
|
||||
case 'Identifier': {
|
||||
// 1. Let bindingId be StringValue of BindingIdentifier.
|
||||
let bindingId = param.name;
|
||||
|
||||
// 2. Let lhs be ? ResolveBinding(bindingId, environment).
|
||||
let lhs = ResolveBinding(realm, param.name, strict, environment);
|
||||
|
||||
// Initialized later in the algorithm.
|
||||
let v;
|
||||
|
||||
// 3. If iteratorRecord.[[Done]] is false, then
|
||||
if (iteratorRecord.$Done === false) {
|
||||
// a. Let next be IteratorStep(iteratorRecord.[[Iterator]]).
|
||||
let next;
|
||||
try {
|
||||
next = IteratorStep(realm, iteratorRecord.$Iterator);
|
||||
} catch (e) {
|
||||
// b. If next is an abrupt completion, set iteratorRecord.[[Done]] to true.
|
||||
if (e instanceof AbruptCompletion) {
|
||||
iteratorRecord.$Done = true;
|
||||
}
|
||||
|
||||
// c. ReturnIfAbrupt(next).
|
||||
throw e;
|
||||
}
|
||||
|
||||
// d. If next is false, set iteratorRecord.[[Done]] to true.
|
||||
if (next === false) {
|
||||
iteratorRecord.$Done = true;
|
||||
// Normally this assignment would be done in step 4, but we do it
|
||||
// here so that Flow knows `v` will always be initialized by step 5.
|
||||
v = new UndefinedValue(realm);
|
||||
} else { // e. Else,
|
||||
// i. Let v be IteratorValue(next).
|
||||
try {
|
||||
v = IteratorValue(realm, next);
|
||||
} catch (e) {
|
||||
// ii. If v is an abrupt completion, set iteratorRecord.[[Done]] to true.
|
||||
if (e instanceof AbruptCompletion) {
|
||||
iteratorRecord.$Done = true;
|
||||
}
|
||||
|
||||
// iii. ReturnIfAbrupt(v).
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
} else { // 4. If iteratorRecord.[[Done]] is true, let v be undefined.
|
||||
v = new UndefinedValue(realm);
|
||||
}
|
||||
|
||||
// TODO:
|
||||
// 5. If Initializer is present and v is undefined, then
|
||||
// a. Let defaultValue be the result of evaluating Initializer.
|
||||
// b. Let v be ? GetValue(defaultValue).
|
||||
// c. If IsAnonymousFunctionDefinition(Initializer) is true, then
|
||||
// i. Let hasNameProperty be ? HasOwnProperty(v, "name").
|
||||
// ii. If hasNameProperty is false, perform SetFunctionName(v, bindingId).
|
||||
|
||||
// 6. If environment is undefined, return ? PutValue(lhs, v).
|
||||
if (!environment) {
|
||||
PutValue(realm, lhs, v);
|
||||
break;
|
||||
}
|
||||
|
||||
// 7. Return InitializeReferencedBinding(lhs, v).
|
||||
InitializeReferencedBinding(realm, lhs, v);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
throw new ThrowCompletion(new StringValue(realm, "only plain identifiers are supported in parameter lists"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ECMA262 12.1.5.1
|
||||
export function InitializeBoundName(realm: Realm, name: string, value: Value, environment: void | LexicalEnvironment) {
|
||||
// 1. Assert: Type(name) is String.
|
||||
|
@ -21,8 +21,10 @@ import { OrdinaryCreateFromConstructor, CreateUnmappedArgumentsObject, CreateMap
|
||||
import { OrdinaryCallEvaluateBody, OrdinaryCallBindThis, PrepareForOrdinaryCall, Call } from "./call.js";
|
||||
import { SameValue } from "../methods/abstract.js";
|
||||
import { Construct } from "../methods/construct.js";
|
||||
import { IteratorBindingInitialization } from "../methods/environment.js";
|
||||
import { joinPossiblyNormalCompletionWithAbruptCompletion, composePossiblyNormalCompletions,
|
||||
BoundNames, ContainsExpression, GetActiveScriptOrModule, UpdateEmpty } from "../methods/index.js";
|
||||
import { CreateListIterator } from "../methods/iterator.js";
|
||||
import { PutValue } from "./properties.js";
|
||||
import traverse from "../traverse.js";
|
||||
import invariant from "../invariant.js";
|
||||
@ -291,42 +293,20 @@ export function FunctionDeclarationInstantiation(realm: Realm, func: FunctionVal
|
||||
}
|
||||
|
||||
// 23. Let iteratorRecord be Record {[[Iterator]]: CreateListIterator(argumentsList), [[Done]]: false}.
|
||||
let iteratorRecord = 0;
|
||||
let iteratorRecord = {
|
||||
$Iterator: CreateListIterator(realm, argumentsList),
|
||||
$Done: false,
|
||||
};
|
||||
|
||||
// 24. If hasDuplicates is true, then
|
||||
if (hasDuplicates === true) {
|
||||
// a. Perform ? IteratorBindingInitialization for formals with iteratorRecord and undefined as arguments.
|
||||
invariant(formals !== undefined);
|
||||
for (let i = 0; i < formals.length; ++i) {
|
||||
let param = formals[i];
|
||||
|
||||
switch (param.type) {
|
||||
case "Identifier":
|
||||
let value = argumentsList[iteratorRecord] || realm.intrinsics.undefined;
|
||||
++iteratorRecord;
|
||||
let lhs = ResolveBinding(realm, param.name, strict);
|
||||
PutValue(realm, lhs, value);
|
||||
break;
|
||||
default:
|
||||
throw new ThrowCompletion(new StringValue(realm, "only plain identifiers are supported in parameter lists"));
|
||||
}
|
||||
}
|
||||
IteratorBindingInitialization(realm, formals, iteratorRecord, strict);
|
||||
} else { // 25. Else,
|
||||
// a. Perform ? IteratorBindingInitialization for formals with iteratorRecord and env as arguments.
|
||||
invariant(formals !== undefined);
|
||||
for (let i = 0; i < formals.length; ++i) {
|
||||
let param = formals[i];
|
||||
|
||||
switch (param.type) {
|
||||
case "Identifier":
|
||||
let value = argumentsList[iteratorRecord] || realm.intrinsics.undefined;
|
||||
++iteratorRecord;
|
||||
envRec.InitializeBinding(param.name, value);
|
||||
break;
|
||||
default:
|
||||
throw new ThrowCompletion(new StringValue(realm, "only plain identifiers are supported in parameter lists"));
|
||||
}
|
||||
}
|
||||
IteratorBindingInitialization(realm, formals, iteratorRecord, strict, env);
|
||||
}
|
||||
|
||||
|
||||
|
@ -12,7 +12,14 @@
|
||||
import type { Realm } from "../realm.js";
|
||||
import type { CallableObjectValue } from "../types.js";
|
||||
import { ThrowCompletion, AbruptCompletion } from "../completions.js";
|
||||
import { NumberValue, ObjectValue, UndefinedValue, Value } from "../values/index.js";
|
||||
import {
|
||||
NumberValue,
|
||||
StringValue,
|
||||
ObjectValue,
|
||||
UndefinedValue,
|
||||
NativeFunctionValue,
|
||||
Value,
|
||||
} from "../values/index.js";
|
||||
import {
|
||||
GetMethod,
|
||||
Call,
|
||||
@ -23,6 +30,8 @@ import {
|
||||
} from "./index.js";
|
||||
import invariant from "../invariant.js";
|
||||
import type { IterationKind } from "../types.js";
|
||||
import { SameValue } from "./abstract.js";
|
||||
import { CreateMethodProperty, CreateIterResultObject } from "./create.js";
|
||||
|
||||
// ECMA262 7.4.1
|
||||
export function GetIterator(realm: Realm, obj: Value = realm.intrinsics.undefined, method?: Value): ObjectValue {
|
||||
@ -98,6 +107,87 @@ export function IteratorNext(realm: Realm, iterator: Value, value?: Value): Obje
|
||||
return result;
|
||||
}
|
||||
|
||||
// ECMA262 7.4.8
|
||||
export function CreateListIterator(realm: Realm, list: Array<Value>): ObjectValue {
|
||||
// 1. Let iterator be ObjectCreate(%IteratorPrototype%, « [[IteratorNext]], [[IteratedList]], [[ListIteratorNextIndex]] »).
|
||||
let iterator = ObjectCreate(realm, realm.intrinsics.IteratorPrototype, {
|
||||
$IteratorNext: undefined,
|
||||
$IteratedList: undefined,
|
||||
$ListIteratorNextIndex: undefined,
|
||||
});
|
||||
|
||||
// 2. Set iterator's [[IteratedList]] internal slot to list.
|
||||
iterator.$IteratedList = list;
|
||||
|
||||
// 3. Set iterator's [[ListIteratorNextIndex]] internal slot to 0.
|
||||
iterator.$ListIteratorNextIndex = 0;
|
||||
|
||||
// 4. Let next be a new built-in function object as defined in ListIterator next (7.4.8.1).
|
||||
let next = ListIterator_next(realm);
|
||||
|
||||
// 5. Set iterator's [[IteratorNext]] internal slot to next.
|
||||
iterator.$IteratorNext = next;
|
||||
|
||||
// 6. Perform CreateMethodProperty(iterator, "next", next).
|
||||
CreateMethodProperty(realm, iterator, new StringValue(realm, 'next'), next);
|
||||
|
||||
// 7. Return iterator.
|
||||
return iterator;
|
||||
}
|
||||
|
||||
// ECMA262 7.4.8.1
|
||||
function ListIterator_next(realm: Realm): NativeFunctionValue {
|
||||
let func = new NativeFunctionValue(realm, undefined, "next", 0, (context: ObjectValue) => {
|
||||
// 1. Let O be the this value.
|
||||
let O = context;
|
||||
|
||||
// 2. Let f be the active function object.
|
||||
let f = func;
|
||||
|
||||
// 3. If O does not have a [[IteratorNext]] internal slot, throw a TypeError exception.
|
||||
if (!O.$IteratorNext) {
|
||||
throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError, "O does not have an [[IteratorNext]] internal slot");
|
||||
}
|
||||
|
||||
// 4. Let next be the value of the [[IteratorNext]] internal slot of O.
|
||||
let next = O.$IteratorNext;
|
||||
|
||||
// 5. If SameValue(f, next) is false, throw a TypeError exception.
|
||||
if (!SameValue(realm, f, next)) {
|
||||
throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError);
|
||||
}
|
||||
|
||||
// 6. If O does not have an [[IteratedList]] internal slot, throw a TypeError exception.
|
||||
if (!O.$IteratedList) {
|
||||
throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError, "O does not have an [[IteratedList]] internal slot");
|
||||
}
|
||||
|
||||
// 7. Let list be the value of the [[IteratedList]] internal slot of O.
|
||||
let list = O.$IteratedList;
|
||||
|
||||
// 8. Let index be the value of the [[ListIteratorNextIndex]] internal slot of O.
|
||||
// Default to 0 for Flow.
|
||||
let index = O.$ListIteratorNextIndex || 0;
|
||||
|
||||
// 9. Let len be the number of elements of list.
|
||||
let len = list.length;
|
||||
|
||||
// 10. If index ≥ len, then
|
||||
if (index >= len) {
|
||||
// a. Return CreateIterResultObject(undefined, true).
|
||||
return CreateIterResultObject(realm, new UndefinedValue(realm), true);
|
||||
}
|
||||
|
||||
// 11. Set the value of the [[ListIteratorNextIndex]] internal slot of O to index+1.
|
||||
O.$ListIteratorNextIndex = index + 1;
|
||||
|
||||
// 12. Return CreateIterResultObject(list[index], false).
|
||||
return CreateIterResultObject(realm, list[index], false);
|
||||
});
|
||||
|
||||
return func;
|
||||
}
|
||||
|
||||
// ECMA262 23.1.5.1
|
||||
export function CreateMapIterator(realm: Realm, map: Value, kind: IterationKind): ObjectValue {
|
||||
// 1. If Type(map) is not Object, throw a TypeError exception.
|
||||
|
@ -100,6 +100,11 @@ export default class ObjectValue extends ConcreteValue {
|
||||
$Capabilities: void | PromiseCapability;
|
||||
$RemainingElements: void | { value: number };
|
||||
|
||||
// iterator
|
||||
$IteratedList: void | Array<Value>;
|
||||
$ListIteratorNextIndex: void | number;
|
||||
$IteratorNext: void | NativeFunctionValue;
|
||||
|
||||
// set
|
||||
$SetIterationKind: void | IterationKind;
|
||||
$SetNextIndex: void | number;
|
||||
|
Loading…
Reference in New Issue
Block a user