Created
September 25, 2018 08:58
-
-
Save TimothyGu/93a41838d1f069ab312f131785ae65be to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
From adafabcd57702bd2a73207962f81bdc94d5278de Mon Sep 17 00:00:00 2001 | |
From: Timothy Gu <[email protected]> | |
Date: Tue, 25 Sep 2018 00:01:16 -0700 | |
Subject: [PATCH] for-in loop | |
engine262/src/runtime-semantics/ForStatement.mjs | |
149:7 error 'BindingInstantiation_ForDeclaration' is not defined no-undef | |
169:18 error 'DestructuringAssignmentEvaluation_AssignmentPattern' is not defined no-undef | |
--- | |
src/ast.mjs | 45 ++++- | |
src/evaluator.mjs | 13 +- | |
src/runtime-semantics/BindingInitialization.mjs | 23 +++ | |
src/runtime-semantics/BlockStatement.mjs | 4 +- | |
src/runtime-semantics/BreakableStatement.mjs | 60 ++++++ | |
src/runtime-semantics/EvaluateBody.mjs | 14 +- | |
src/runtime-semantics/ForStatement.mjs | 242 +++++++++++++++++++++--- | |
src/runtime-semantics/all.mjs | 3 +- | |
src/static-semantics/IsDestructuring.mjs | 26 +++ | |
src/static-semantics/all.mjs | 1 + | |
10 files changed, 388 insertions(+), 43 deletions(-) | |
create mode 100644 src/runtime-semantics/BreakableStatement.mjs | |
create mode 100644 src/static-semantics/IsDestructuring.mjs | |
diff --git a/src/ast.mjs b/src/ast.mjs | |
index 7169a50..665bf7b 100644 | |
--- a/src/ast.mjs | |
+++ b/src/ast.mjs | |
@@ -591,24 +591,62 @@ export function isIterationStatement(node) { | |
|| node.type === 'ForOfStatement'; | |
} | |
+// Used in #prod-IterationStatement | |
+export function isDoWhileStatement(node) { | |
+ return node.type === 'DoWhileStatement'; | |
+} | |
+ | |
+// Used in #prod-IterationStatement | |
+export function isWhileStatement(node) { | |
+ return node.type === 'WhileStatement'; | |
+} | |
+ | |
+// Used in #prod-IterationStatement | |
export function isForStatement(node) { | |
return node.type === 'ForStatement'; | |
} | |
+// Used in #prod-IterationStatement | |
export function isForStatementWithExpression(node) { | |
return isForStatement(node) && isExpression(node.init); | |
} | |
+// Used in #prod-IterationStatement | |
export function isForStatementWithVariableStatement(node) { | |
return isForStatement(node) && isVariableStatement(node.init); | |
} | |
+// Used in #prod-IterationStatement | |
export function isForStatementWithLexicalDeclaration(node) { | |
return isForStatement(node) && isLexicalDeclaration(node.init); | |
} | |
-export function isForBinding() { | |
- return false; | |
+// Used in #prod-IterationStatement | |
+export function isForInStatement(node) { | |
+ return node.type === 'ForInStatement'; | |
+} | |
+ | |
+// Used in #prod-IterationStatement | |
+// This covers cases like for ({ a } of b), in which case the { a } is in fact | |
+// parsed as an ObjectLiteral per spec. | |
+export function isForInStatementWithExpression(node) { | |
+ return isForInStatement(node) && node.left.type !== 'VariableDeclaration'; | |
+} | |
+ | |
+// Used in #prod-IterationStatement | |
+export function isForInStatementWithVarForBinding(node) { | |
+ return isForInStatement(node) && isVariableStatement(node.left) | |
+ && !node.left.declarations[0].init; | |
+} | |
+ | |
+// Used in #prod-IterationStatement | |
+export function isForInStatementWithForDeclaration(node) { | |
+ return isForInStatement(node) && isForDeclaration(node.left); | |
+} | |
+ | |
+// #prod-ForBinding | |
+export function isForBinding(node) { | |
+ return isBindingIdentifier(node) || isBindingPattern(node); | |
} | |
// #prod-SwitchStatement | |
@@ -740,6 +778,9 @@ export function isLexicalDeclaration(node) { | |
return node.type === 'VariableDeclaration' && (node.kind === 'let' || node.kind === 'const'); | |
} | |
+// #prod-ForDeclaration | |
+export const isForDeclaration = isLexicalDeclaration; | |
+ | |
// #prod-LexicalBinding | |
export function isLexicalBinding(node) { | |
return node.type === 'VariableDeclarator'; | |
diff --git a/src/evaluator.mjs b/src/evaluator.mjs | |
index 58adb24..df5be2b 100644 | |
--- a/src/evaluator.mjs | |
+++ b/src/evaluator.mjs | |
@@ -27,9 +27,9 @@ import { | |
isArrowFunction, | |
isBlockStatement, | |
isBreakStatement, | |
+ isBreakableStatement, | |
isExpressionStatement, | |
isExpressionWithComma, | |
- isForStatement, | |
isFunctionDeclaration, | |
isFunctionExpression, | |
isIdentifierReference, | |
@@ -39,7 +39,6 @@ import { | |
isLiteral, | |
isObjectLiteral, | |
isReturnStatement, | |
- isSwitchStatement, | |
isTemplateLiteral, | |
isThis, | |
isThrowStatement, | |
@@ -63,12 +62,12 @@ import { | |
Evaluate_BinaryBitwiseExpression, | |
Evaluate_BlockStatement, | |
Evaluate_BreakStatement, | |
+ Evaluate_BreakableStatement, | |
Evaluate_CallExpression, | |
Evaluate_ConditionalExpression, | |
Evaluate_EqualityExpression, | |
Evaluate_ExponentiationExpression, | |
Evaluate_ExpressionWithComma, | |
- Evaluate_ForStatement, | |
Evaluate_FunctionDeclaration, | |
Evaluate_FunctionExpression, | |
Evaluate_Identifier, | |
@@ -84,7 +83,6 @@ import { | |
Evaluate_RelationalExpression, | |
Evaluate_ReturnStatement, | |
Evaluate_ShiftExpression, | |
- Evaluate_SwitchStatement, | |
Evaluate_TemplateLiteral, | |
Evaluate_ThisExpression, | |
Evaluate_ThrowStatement, | |
@@ -155,8 +153,8 @@ function Evaluate_StatementListItem(StatementListItem) { | |
case isIfStatement(StatementListItem): | |
return Evaluate_IfStatement(StatementListItem); | |
- case isForStatement(StatementListItem): | |
- return Evaluate_ForStatement(StatementListItem); | |
+ case isBreakableStatement(StatementListItem): | |
+ return Evaluate_BreakableStatement(StatementListItem); | |
// case isContinueStatement(StatementListItem): | |
// return Evaluate_ContinueStatement(StatementListItem); | |
@@ -170,9 +168,6 @@ function Evaluate_StatementListItem(StatementListItem) { | |
case isWithStatement(StatementListItem): | |
return Evaluate_WithStatement(StatementListItem); | |
- case isSwitchStatement(StatementListItem): | |
- return Evaluate_SwitchStatement(StatementListItem); | |
- | |
case isThrowStatement(StatementListItem): | |
return Evaluate_ThrowStatement(StatementListItem.argument); | |
diff --git a/src/runtime-semantics/BindingInitialization.mjs b/src/runtime-semantics/BindingInitialization.mjs | |
index 6dd664c..601fff5 100644 | |
--- a/src/runtime-semantics/BindingInitialization.mjs | |
+++ b/src/runtime-semantics/BindingInitialization.mjs | |
@@ -77,6 +77,23 @@ export function BindingInitialization_BindingPattern(BindingPattern, value, envi | |
} | |
} | |
+// (implicit) | |
+// ForBinding : | |
+// BindingIdentifier | |
+// BindingPattern | |
+export function BindingInitialization_ForBinding(ForBinding, value, environment) { | |
+ switch (true) { | |
+ case isBindingIdentifier(ForBinding): | |
+ return BindingInitialization_BindingIdentifier(ForBinding, value, environment); | |
+ | |
+ case isBindingPattern(ForBinding): | |
+ return BindingInitialization_BindingPattern(ForBinding, value, environment); | |
+ | |
+ default: | |
+ throw outOfRange('BindingInitialization_ForBinding', ForBinding); | |
+ } | |
+} | |
+ | |
// #sec-destructuring-binding-patterns-runtime-semantics-bindinginitialization | |
// ObjectBindingPattern : | |
// `{` `}` | |
@@ -121,3 +138,9 @@ export function BindingInitialization_CatchParameter(CatchParameter, value, envi | |
throw outOfRange('BindingInitialization_CatchParameter', CatchParameter); | |
} | |
} | |
+ | |
+// #sec-for-in-and-for-of-statements-runtime-semantics-bindinginitialization | |
+// ForDeclaration : LetOrConst ForBinding | |
+export function BindingInitialization_ForDeclaration(ForDeclaration, value, environment) { | |
+ return BindingInitialization_ForBinding(ForDeclaration.declarations[0].id, value, environment); | |
+} | |
diff --git a/src/runtime-semantics/BlockStatement.mjs b/src/runtime-semantics/BlockStatement.mjs | |
index d755831..1212ef0 100644 | |
--- a/src/runtime-semantics/BlockStatement.mjs | |
+++ b/src/runtime-semantics/BlockStatement.mjs | |
@@ -39,9 +39,9 @@ export function BlockDeclarationInstantiation(code, env) { | |
for (const d of declarations) { | |
for (const dn of BoundNames_Declaration(d).map(NewValue)) { | |
if (IsConstantDeclaration(d)) { | |
- X(envRec.CreateImmutableBinding(dn, NewValue(true))); | |
+ X(envRec.CreateImmutableBinding(dn, true)); | |
} else { | |
- X(envRec.CreateMutableBinding(dn, NewValue(false))); | |
+ X(envRec.CreateMutableBinding(dn, false)); | |
} | |
if (isFunctionDeclaration(d) || isGeneratorDeclaration(d) | |
|| isAsyncFunctionDeclaration(d) || isAsyncGeneratorDeclaration(d)) { | |
diff --git a/src/runtime-semantics/BreakableStatement.mjs b/src/runtime-semantics/BreakableStatement.mjs | |
new file mode 100644 | |
index 0000000..4fd2e92 | |
--- /dev/null | |
+++ b/src/runtime-semantics/BreakableStatement.mjs | |
@@ -0,0 +1,60 @@ | |
+import { | |
+ isIterationStatement, | |
+ isSwitchStatement, | |
+} from '../ast.mjs'; | |
+import { | |
+ Completion, | |
+ NormalCompletion, | |
+} from '../completion.mjs'; | |
+import { outOfRange } from '../helpers.mjs'; | |
+import { New as NewValue } from '../value.mjs'; | |
+import { | |
+ Evaluate_SwitchStatement, | |
+ LabelledEvaluation_IterationStatement, | |
+} from './all.mjs'; | |
+ | |
+// #sec-statement-semantics-runtime-semantics-evaluation | |
+// BreakableStatement : | |
+// IterationStatement | |
+// SwitchStatement | |
+export function Evaluate_BreakableStatement(BreakableStatement) { | |
+ const newLabelSet = []; | |
+ return LabelledEvaluation_BreakableStatement(BreakableStatement, newLabelSet); | |
+} | |
+ | |
+// #sec-statement-semantics-runtime-semantics-labelledevaluation | |
+// BreakableStatement : IterationStatement | |
+function LabelledEvaluation_BreakableStatement(BreakableStatement, labelSet) { | |
+ switch (true) { | |
+ case isIterationStatement(BreakableStatement): { | |
+ let stmtResult = LabelledEvaluation_IterationStatement(BreakableStatement, labelSet); | |
+ if (stmtResult.Type === 'break') { | |
+ if (stmtResult.Target === undefined) { | |
+ if (stmtResult.Value === undefined) { | |
+ stmtResult = new NormalCompletion(NewValue(undefined)); | |
+ } else { | |
+ stmtResult = new NormalCompletion(stmtResult.Value); | |
+ } | |
+ } | |
+ } | |
+ return Completion(stmtResult); | |
+ } | |
+ | |
+ case isSwitchStatement(BreakableStatement): { | |
+ let stmtResult = Evaluate_SwitchStatement(BreakableStatement, labelSet); | |
+ if (stmtResult.Type === 'break') { | |
+ if (stmtResult.Target === undefined) { | |
+ if (stmtResult.Value === undefined) { | |
+ stmtResult = new NormalCompletion(NewValue(undefined)); | |
+ } else { | |
+ stmtResult = new NormalCompletion(stmtResult.Value); | |
+ } | |
+ } | |
+ } | |
+ return Completion(stmtResult); | |
+ } | |
+ | |
+ default: | |
+ throw outOfRange('LabelledEvaluation_BreakableStatement', BreakableStatement); | |
+ } | |
+} | |
diff --git a/src/runtime-semantics/EvaluateBody.mjs b/src/runtime-semantics/EvaluateBody.mjs | |
index ed4d6a3..fd8918d 100644 | |
--- a/src/runtime-semantics/EvaluateBody.mjs | |
+++ b/src/runtime-semantics/EvaluateBody.mjs | |
@@ -105,7 +105,7 @@ export function FunctionDeclarationInstantiation(func, argumentsList) { | |
for (const paramName of parameterNames) { | |
const alreadyDeclared = envRec.HasBinding(paramName); | |
if (alreadyDeclared.isFalse()) { | |
- X(envRec.CreateMutableBinding(paramName, NewValue(false))); | |
+ X(envRec.CreateMutableBinding(paramName, false)); | |
if (hasDuplicates === true) { | |
X(envRec.InitializeBinding(paramName, NewValue(undefined))); | |
} | |
@@ -121,9 +121,9 @@ export function FunctionDeclarationInstantiation(func, argumentsList) { | |
ao = CreateMappedArgumentsObject(func, formals, argumentsList, envRec); | |
} | |
if (strict) { | |
- X(envRec.CreateImmutableBinding(NewValue('arguments'), NewValue(false))); | |
+ X(envRec.CreateImmutableBinding(NewValue('arguments'), false)); | |
} else { | |
- X(envRec.CreateMutableBinding(NewValue('arguments'), NewValue(false))); | |
+ X(envRec.CreateMutableBinding(NewValue('arguments'), false)); | |
} | |
envRec.InitializeBinding(NewValue('arguments'), ao); | |
parameterBindings = [...parameterNames, NewValue('arguments')]; | |
@@ -145,7 +145,7 @@ export function FunctionDeclarationInstantiation(func, argumentsList) { | |
for (const n of varNames) { | |
if (!instantiatedVarNames.includes(n)) { | |
instantiatedVarNames.push(n); | |
- X(envRec.CreateMutableBinding(n, NewValue(false))); | |
+ X(envRec.CreateMutableBinding(n, false)); | |
envRec.InitializeBinding(n, NewValue(undefined)); | |
} | |
} | |
@@ -159,7 +159,7 @@ export function FunctionDeclarationInstantiation(func, argumentsList) { | |
for (const n of varNames) { | |
if (!instantiatedVarNames.includes(n)) { | |
instantiatedVarNames.push(n); | |
- X(varEnvRec.CreateMutableBinding(n, NewValue(false))); | |
+ X(varEnvRec.CreateMutableBinding(n, false)); | |
let initialValue; | |
if (!parameterBindings.includes(n) || functionNames.includes(n)) { | |
initialValue = NewValue(undefined); | |
@@ -190,9 +190,9 @@ export function FunctionDeclarationInstantiation(func, argumentsList) { | |
for (const d of lexDeclarations) { | |
for (const dn of BoundNames_LexicalDeclaration.map(NewValue)) { | |
if (IsConstantDeclaration(d)) { | |
- X(lexEnvRec.CreateImmutableBinding(dn, NewValue(true))); | |
+ X(lexEnvRec.CreateImmutableBinding(dn, true)); | |
} else { | |
- X(lexEnvRec.CreateMutableBinding(dn, NewValue(false))); | |
+ X(lexEnvRec.CreateMutableBinding(dn, false)); | |
} | |
} | |
} | |
diff --git a/src/runtime-semantics/ForStatement.mjs b/src/runtime-semantics/ForStatement.mjs | |
index 5d66882..8ef3a27 100644 | |
--- a/src/runtime-semantics/ForStatement.mjs | |
+++ b/src/runtime-semantics/ForStatement.mjs | |
@@ -2,14 +2,23 @@ import { surroundingAgent } from '../engine.mjs'; | |
import { Type, New as NewValue } from '../value.mjs'; | |
import { | |
Assert, | |
+ Call, | |
+ GetIterator, | |
GetValue, | |
- ToBoolean, | |
+ IteratorClose, | |
+ IteratorValue, | |
LoopContinues, | |
+ PutValue, | |
+ ToBoolean, | |
+ ToObject, | |
+ ResolveBinding, | |
+ InitializeReferencedBinding, | |
} from '../abstract-ops/all.mjs'; | |
import { | |
Q, X, ReturnIfAbrupt, | |
Completion, | |
AbruptCompletion, | |
+ BreakCompletion, | |
NormalCompletion, | |
UpdateEmpty, | |
} from '../completion.mjs'; | |
@@ -17,11 +26,23 @@ import { | |
isForStatementWithExpression, | |
isForStatementWithVariableStatement, | |
isForStatementWithLexicalDeclaration, | |
+ isForInStatementWithExpression, | |
+ isForInStatementWithForDeclaration, | |
+ isForInStatementWithVarForBinding, | |
+ isForDeclaration, | |
+ isForBinding, | |
} from '../ast.mjs'; | |
import { | |
IsConstantDeclaration, | |
BoundNames_LexicalDeclaration, | |
+ BoundNames_ForDeclaration, | |
+ IsDestructuring_ForDeclaration, | |
+ IsDestructuring_ForBinding, | |
} from '../static-semantics/all.mjs'; | |
+import { | |
+ BindingInitialization_ForBinding, | |
+ BindingInitialization_ForDeclaration, | |
+} from './all.mjs'; | |
import { Evaluate_Expression, Evaluate_Statement } from '../evaluator.mjs'; | |
import { NewDeclarativeEnvironment } from '../environment.mjs'; | |
import { outOfRange } from '../helpers.mjs'; | |
@@ -36,7 +57,7 @@ function CreatePerIterationEnvironment(perIterationBindings) { | |
const thisIterationEnv = NewDeclarativeEnvironment(outer); | |
const thisIterationEnvRec = thisIterationEnv.EnvironmentRecord; | |
for (const bn of perIterationBindings) { | |
- X(thisIterationEnvRec.CreateMutableBinding(bn, NewValue(false))); | |
+ X(thisIterationEnvRec.CreateMutableBinding(bn, false)); | |
const lastValue = Q(lastIterationEnvRec.GetBindingValue(bn, NewValue(true))); | |
thisIterationEnvRec.InitializeBinding(bn, lastValue); | |
} | |
@@ -72,49 +93,226 @@ function ForBodyEvaluation(test, increment, stmt, perIterationBindings, labelSet | |
} | |
} | |
+function ForInOfHeadEvaluation(TDZnames, expr, iterationKind) { | |
+ const oldEnv = surroundingAgent.runningExecutionContext.LexicalEnvironment; | |
+ if (TDZnames.length > 0) { | |
+ Assert(new Set(TDZnames).size === TDZnames.length); | |
+ const TDZ = NewDeclarativeEnvironment(oldEnv); | |
+ const TDZEnvRec = TDZ.EnvironmentRecord; | |
+ for (const name of TDZnames) { | |
+ X(TDZEnvRec.CreateMutableBinding(name, false)); | |
+ } | |
+ surroundingAgent.runningExecutionContext.LexicalEnvironment = TDZ; | |
+ } | |
+ const exprRef = Evaluate_Expression(expr); | |
+ surroundingAgent.runningExecutionContext.LexicalEnvironment = oldEnv; | |
+ const exprValue = Q(GetValue(exprRef)); | |
+ if (iterationKind === 'enumerate') { | |
+ if (Type(exprValue) === 'Undefined' || Type(exprValue) === 'Null') { | |
+ return new BreakCompletion(undefined); | |
+ } | |
+ const obj = X(ToObject(exprValue)); | |
+ return Q(EnumerateObjectProperties(obj)); | |
+ } else { | |
+ Assert(iterationKind === 'iterate' || iterationKind === 'async-iterate'); | |
+ const iteratorHint = iterationKind === 'async-iterate' ? 'async' : 'hint'; | |
+ return Q(GetIterator(exprValue, iteratorHint)); | |
+ } | |
+} | |
+ | |
+function ForInOfBodyEvaluation(lhs, stmt, iteratorRecord, iterationKind, lhsKind, labelSet/* , iteratorKind = 'sync' */) { | |
+ const oldEnv = surroundingAgent.runningExecutionContext.LexicalEnvironment; | |
+ let V = NewValue(undefined); | |
+ const destructuring = lhs.type === 'VariableDeclaration' | |
+ ? IsDestructuring_ForDeclaration(lhs) : IsDestructuring_ForBinding(lhs); | |
+ let assignmentPattern; | |
+ if (destructuring && lhsKind === 'assignment') { | |
+ assignmentPattern = lhs; | |
+ } | |
+ while (true) { | |
+ const nextResult = Q(Call(iteratorRecord.NextMethod, iteratorRecord.Iterator, [])); | |
+ // if (iteratorKind === 'async') | |
+ if (Type(nextResult) !== 'Object') { | |
+ return surroundingAgent.Throw('TypeError'); | |
+ } | |
+ const nextValue = Q(IteratorValue(nextResult)); | |
+ let iterationEnv; | |
+ let lhsRef; | |
+ if (lhsKind === 'assignment' || lhsKind === 'varBinding') { | |
+ if (!destructuring) { | |
+ lhsRef = Evaluate_Expression(lhs); | |
+ } | |
+ } else { | |
+ Assert(lhsKind === 'lexicalBinding'); | |
+ Assert(isForDeclaration(lhs)); | |
+ iterationEnv = NewDeclarativeEnvironment(oldEnv); | |
+ BindingInstantiation_ForDeclaration(lhs, iterationEnv); | |
+ surroundingAgent.runningExecutionContext.LexicalEnvironment = iterationEnv; | |
+ if (!destructuring) { | |
+ const lhsNames = BoundNames_ForDeclaration(lhs); | |
+ Assert(lhsNames.length === 1); | |
+ const [lhsName] = lhsNames; | |
+ lhsRef = X(ResolveBinding(lhsName)); | |
+ } | |
+ } | |
+ let status; | |
+ if (!destructuring) { | |
+ if (lhsRef instanceof AbruptCompletion) { | |
+ status = lhsRef; | |
+ } else if (lhsKind === 'lexicalBinding') { | |
+ status = InitializeReferencedBinding(lhsRef, nextValue); | |
+ } else { | |
+ status = PutValue(lhsRef, nextValue); | |
+ } | |
+ } else { | |
+ if (lhsKind === 'assignment') { | |
+ status = DestructuringAssignmentEvaluation_AssignmentPattern(assignmentPattern, nextValue); | |
+ } else if (lhsKind === 'varBinding') { | |
+ Assert(isForBinding(lhs)); | |
+ status = BindingInitialization_ForBinding(lhs, nextValue, NewValue(undefined)); | |
+ } else { | |
+ Assert(lhsKind === 'lexicalBinding'); | |
+ Assert(isForDeclaration(lhs)); | |
+ status = BindingInitialization_ForDeclaration(lhs, nextValue, iterationEnv); | |
+ } | |
+ } | |
+ if (status instanceof AbruptCompletion) { | |
+ surroundingAgent.runningExecutionContext.LexicalEnvironment = oldEnv; | |
+ // if (iteratorKind === 'async') { | |
+ // return Q(AsyncIteratorClose(iteratorRecord, status)); | |
+ // } | |
+ if (iterationKind === 'enumerate') { | |
+ return status; | |
+ } else { | |
+ Assert(iterationKind === 'iterate'); | |
+ return Q(IteratorClose(iteratorRecord, status)); | |
+ } | |
+ } | |
+ const result = Evaluate_Statement(stmt); | |
+ surroundingAgent.runningExecutionContext.LexicalEnvironment = oldEnv; | |
+ if (LoopContinues(result, labelSet).isFalse()) { | |
+ if (iterationKind === 'enumerate') { | |
+ return Completion(UpdateEmpty(result, V)); | |
+ } else { | |
+ Assert(iterationKind === 'iterate'); | |
+ status = UpdateEmpty(result, V); | |
+ // if (iteratorKind === 'async') { | |
+ // return Q(AsyncIteratorClose(iteratorRecord, status)); | |
+ // } | |
+ return Q(IteratorClose(iteratorRecord, status)); | |
+ } | |
+ } | |
+ if (result.Value !== undefined) { | |
+ V = result.Value; | |
+ } | |
+ } | |
+} | |
+ | |
+// #sec-do-while-statement-runtime-semantics-labelledevaluation | |
+// IterationStatement : `do` Statement `while` `(` Expression `)` `;` | |
+// | |
+// #sec-while-statement-runtime-semantics-labelledevaluation | |
+// IterationStatement : `while` `(` Expression `)` Statement | |
+// | |
// #sec-for-statement-runtime-semantics-labelledevaluation | |
-// IterationStatement : | |
-// `for` `(` Expression `;` Expression `;` Expression `)` Statement | |
-// `for` `(` `var` VariableDeclarationList `;` Expression `;` Expression `)` Statement | |
-// `for` `(` LexicalDeclarationExpression `;` Expression `)` Statement | |
-export function Evaluate_ForStatement(ForStatement, labelSet = []) { | |
+// IterationStatement : | |
+// `for` `(` Expression `;` Expression `;` Expression `)` Statement | |
+// `for` `(` `var` VariableDeclarationList `;` Expression `;` Expression `)` Statement | |
+// `for` `(` LexicalDeclarationExpression `;` Expression `)` Statement | |
+// | |
+// #sec-for-in-and-for-of-statements-runtime-semantics-labelledevaluation | |
+// IterationStatement : | |
+// `for` `(` LeftHandSideExpression `in` Expression `)` Statement | |
+// `for` `(` `var` ForBinding `in` Expression `)` Statement | |
+// `for` `(` ForDeclaration `in` Expression `)` Statement | |
+// `for` `(` LeftHandSideExpression `of` AssignmentExpression `)` Statement | |
+// `for` `(` `var` ForBinding `of` AssignmentExpression `)` Statement | |
+// `for` `(` ForDeclaration `of` AssignmentExpression `)` Statement | |
+// `for` `await` `(` LeftHandSideExpression `of` AssignmentExpression `)` Statement | |
+// `for` `await` `(` `var` ForBinding `of` AssignmentExpression `)` Statement | |
+// `for` `await` `(` ForDeclaration `of` AssignmentExpression `)` Statement | |
+export function LabelledEvaluation_IterationStatement(IterationStatement, labelSet) { | |
switch (true) { | |
- case isForStatementWithExpression(ForStatement): | |
- if (ForStatement.init) { | |
- const exprRef = Evaluate_Expression(ForStatement.init); | |
+ // case isDoWhileStatement(IterationStatement): | |
+ | |
+ // case isWhileStatement(IterationStatement): | |
+ | |
+ case isForStatementWithExpression(IterationStatement): | |
+ if (IterationStatement.init) { | |
+ const exprRef = Evaluate_Expression(IterationStatement.init); | |
Q(GetValue(exprRef)); | |
} | |
- return Q(ForBodyEvaluation(ForStatement.test, ForStatement.update, ForStatement.body, [], labelSet)); | |
- case isForStatementWithVariableStatement(ForStatement): { | |
- let varDcl = Evaluate_Statement(ForStatement.init); | |
+ return Q(ForBodyEvaluation(IterationStatement.test, IterationStatement.update, IterationStatement.body, [], labelSet)); | |
+ | |
+ case isForStatementWithVariableStatement(IterationStatement): { | |
+ let varDcl = Evaluate_Statement(IterationStatement.init); | |
ReturnIfAbrupt(varDcl); | |
- return Q(ForBodyEvaluation(ForStatement.test, ForStatement.update, ForStatement.body, [], labelSet)); | |
+ return Q(ForBodyEvaluation(IterationStatement.test, IterationStatement.update, IterationStatement.body, [], labelSet)); | |
} | |
- case isForStatementWithLexicalDeclaration(ForStatement): { | |
+ | |
+ case isForStatementWithLexicalDeclaration(IterationStatement): { | |
const oldEnv = surroundingAgent.runningExecutionContext.LexicalEnvironment; | |
const loopEnv = NewDeclarativeEnvironment(oldEnv); | |
const loopEnvRec = loopEnv.EnvironmentRecord; | |
- const isConst = IsConstantDeclaration(ForStatement.init); | |
- const boundNames = BoundNames_LexicalDeclaration(ForStatement.init).map(NewValue); | |
+ const isConst = IsConstantDeclaration(IterationStatement.init); | |
+ const boundNames = BoundNames_LexicalDeclaration(IterationStatement.init).map(NewValue); | |
for (const dn of boundNames) { | |
if (isConst) { | |
- X(loopEnvRec.CreateImmutableBinding(dn, NewValue(true))); | |
+ X(loopEnvRec.CreateImmutableBinding(dn, true)); | |
} else { | |
- X(loopEnvRec.CreateMutableBinding(dn, NewValue(true))); | |
+ X(loopEnvRec.CreateMutableBinding(dn, true)); | |
} | |
} | |
surroundingAgent.runningExecutionContext.LexicalEnvironment = loopEnv; | |
- const forDcl = Evaluate_Statement(ForStatement.init); | |
+ const forDcl = Evaluate_Statement(IterationStatement.init); | |
if (forDcl instanceof AbruptCompletion) { | |
surroundingAgent.runningExecutionContext.LexicalEnvironment = oldEnv; | |
return Completion(forDcl); | |
} | |
const perIterationLets = isConst ? [] : boundNames; | |
- const bodyResult = ForBodyEvaluation(ForStatement.test, ForStatement.update, ForStatement.body, perIterationLets, labelSet); | |
+ const bodyResult = ForBodyEvaluation(IterationStatement.test, IterationStatement.update, IterationStatement.body, perIterationLets, labelSet); | |
surroundingAgent.runningExecutionContext.LexicalEnvironment = oldEnv; | |
return Completion(bodyResult); | |
} | |
+ | |
+ case isForInStatementWithExpression(IterationStatement): { | |
+ const { | |
+ left: LeftHandSideExpression, | |
+ right: Expression, | |
+ body: Statement, | |
+ } = IterationStatement; | |
+ const keyResult = Q(ForInOfHeadEvaluation([], Expression, 'enumerate')); | |
+ return Q(ForInOfBodyEvaluation(LeftHandSideExpression, Statement, keyResult, 'enumerate', 'assignment', labelSet)); | |
+ } | |
+ | |
+ case isForInStatementWithVarForBinding(IterationStatement): { | |
+ const { | |
+ left: { | |
+ declarations: [{ id: ForBinding }], | |
+ }, | |
+ right: Expression, | |
+ body: Statement, | |
+ } = IterationStatement; | |
+ const keyResult = Q(ForInOfHeadEvaluation([], Expression, 'enumerate')); | |
+ return Q(ForInOfBodyEvaluation(ForBinding, Statement, keyResult, 'enumerate', 'varBinding', labelSet)); | |
+ } | |
+ | |
+ case isForInStatementWithForDeclaration(IterationStatement): { | |
+ const { | |
+ left: ForDeclaration, | |
+ right: Expression, | |
+ body: Statement, | |
+ } = IterationStatement; | |
+ const keyResult = Q(ForInOfHeadEvaluation(BoundNames_ForDeclaration(ForDeclaration), Expression, 'enumerate')); | |
+ return Q(ForInOfBodyEvaluation(ForDeclaration, Statement, keyResult, 'enumerate', 'lexicalBinding', labelSet)); | |
+ } | |
+ | |
default: | |
- throw outOfRange('Evaluate_ForStatement', ForStatement); | |
+ throw outOfRange('LabelledEvaluation_IterationStatement', IterationStatement); | |
} | |
} | |
+ | |
+// #sec-enumerate-object-properties | |
+function EnumerateObjectProperties(O) { | |
+ Assert(Type(O) === 'Object'); | |
+} | |
diff --git a/src/runtime-semantics/all.mjs b/src/runtime-semantics/all.mjs | |
index e865edf..a0d193a 100644 | |
--- a/src/runtime-semantics/all.mjs | |
+++ b/src/runtime-semantics/all.mjs | |
@@ -7,6 +7,7 @@ export * from './BindingInitialization.mjs'; | |
export * from './BitwiseOperators.mjs'; | |
export * from './BlockStatement.mjs'; | |
export * from './BreakStatement.mjs'; | |
+export * from './BreakableStatement.mjs'; | |
export * from './CallExpression.mjs'; | |
export * from './ConditionalExpression.mjs'; | |
export * from './EqualityExpression.mjs'; | |
@@ -33,8 +34,8 @@ export * from './NewExpression.mjs'; | |
export * from './ObjectLiteral.mjs'; | |
export * from './PropertyBindingInitialization.mjs'; | |
export * from './RelationalOperators.mjs'; | |
-export * from './ReturnStatement.mjs'; | |
export * from './RestBindingInitialization.mjs'; | |
+export * from './ReturnStatement.mjs'; | |
export * from './ShiftExpression.mjs'; | |
export * from './SwitchStatement.mjs'; | |
export * from './TemplateLiteral.mjs'; | |
diff --git a/src/static-semantics/IsDestructuring.mjs b/src/static-semantics/IsDestructuring.mjs | |
new file mode 100644 | |
index 0000000..cc0387e | |
--- /dev/null | |
+++ b/src/static-semantics/IsDestructuring.mjs | |
@@ -0,0 +1,26 @@ | |
+import { outOfRange } from '../helpers.mjs'; | |
+import { | |
+ isBindingIdentifier, | |
+ isBindingPattern, | |
+} from '../ast.mjs'; | |
+ | |
+// #sec-for-in-and-for-of-statements-static-semantics-isdestructuring | |
+// ForDeclaration : LetOrConst ForBinding | |
+export function IsDestructuring_ForDeclaration(ForDeclaration) { | |
+ return IsDestructuring_ForBinding(ForDeclaration.declarations[0].id); | |
+} | |
+ | |
+// #sec-for-in-and-for-of-statements-static-semantics-isdestructuring | |
+// ForBinding : | |
+// BindingIdentifier | |
+// BindingPattern | |
+export function IsDestructuring_ForBinding(ForBinding) { | |
+ switch (true) { | |
+ case isBindingIdentifier(ForBinding): | |
+ return false; | |
+ case isBindingPattern(ForBinding): | |
+ return true; | |
+ default: | |
+ throw outOfRange('IsDestructuring_ForBinding', ForBinding); | |
+ } | |
+} | |
diff --git a/src/static-semantics/all.mjs b/src/static-semantics/all.mjs | |
index e6a825c..80ae6f7 100644 | |
--- a/src/static-semantics/all.mjs | |
+++ b/src/static-semantics/all.mjs | |
@@ -4,6 +4,7 @@ export * from './ContainsUseStrict.mjs'; | |
export * from './DeclarationPart.mjs'; | |
export * from './ExpectedArgumentCount.mjs'; | |
export * from './HasInitializer.mjs'; | |
+export * from './IsDestructuring.mjs'; | |
export * from './LexicallyDeclaredNames.mjs'; | |
export * from './LexicallyScopedDeclarations.mjs'; | |
export * from './TopLevelLexicallyDeclaredNames.mjs'; | |
-- | |
2.11.0 | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment