Binary AST

The binary AST is isomorphic to ECMA-262 Syntactic Grammar. That is, an instance of a production of the binary AST grammar, or a binary AST Node, corresponds to some Parse Node in the ECMA-262 syntactic grammar. This document specifies the following things.

  1. The tree grammar itself described in IDL and its well-formedness.
  2. The transformation abstract operation Ecmaify(binaryAST) from binary AST Nodes to Parse Nodes by case analysis.
  3. TODO: The similarity Static Semantics ParseNodesAreSimilar.
  4. The evaluation of binary AST input.

A compliant binary AST Encoder, for a source text that matches either the Script or Module goal symbol to produce a Parse Node N, must produce a binary AST Node B such that ParseNodesAreSimilar(Ecmaify(B), N) is true.

The inverse of Ecmaify, Unecmaify, is not specified here. The inverse transform is the encoding of Parse Nodes. For B and N as above, for all M such that ParseNodesAreSimilar(M, N) is true, Unecmaify(M) is B.

1Tree Grammar

This section is derived from Shift AST Spec and parts are Copyright 2014-2017 Shape Security, Inc.

Unlike the Shift AST spec, interface types are not used to inherit fields to control over ordering of fields. Type hierarchies that are not used to discriminate are collapsed to make space costs simple. Nor are they used to discriminate types, for which explicitly discriminated unions types are used.

Note
Whereas Shift AST's design principle is ease of search-and-replace of node types, binary AST's design principle is ease of verification and ease of associating different behaviors with syntactically different (but possibly lexically similar) productions.

The grammar is presented in WebIDL with the [TypeIndicator] and [NonEmpty] extensions per Shift AST spec. The [Lazy] extension serves as a hint to the surface encoding that the [Lazy] attribute should be skippable in the byte stream in constant time. The typedefs of or types are to be read as recursive sum types. In text below, the "is a Foo" prose is shorthand for checking the node's type attribute being equal to "Foo".

// Type aliases and enums.

typedef FrozenArray<(SpreadElement or Expression)> Arguments;
typedef DOMString string;

//  Identifier:: IdentifierName but not ReservedWord
typedef string Identifier;
typedef string IdentifierName;

typedef string Label;

enum VariableDeclarationKind {
  "var",
  "let",
  "const"
};

enum CompoundAssignmentOperator {
  "+=",
  "-=",
  "*=",
  "/=",
  "%=",
  "**=",
  "<<=",
  ">>=",
  ">>>=",
  "|=",
  "^=",
  "&="
};

enum BinaryOperator {
  ",",
  "||",
  "&&",
  "|",
  "^",
  "&",
  "==",
  "!=",
  "===",
  "!==",
  "<",
  "<=",
  ">",
  ">=",
  "in",
  "instanceof",
  "<<",
  ">>",
  ">>>",
  "+",
  "-",
  "*",
  "/",
  "%",
  "**",
};

enum UnaryOperator {
  "+",
  "-",
  "!",
  "~",
  "typeof",
  "void",
  "delete"
};

enum UpdateOperator {
  "++",
  "--"
};

enum AssertedDeclaredKind {
  "var",
  "non-const lexical",
  "const lexical"
};

// deferred assertions

interface AssertedDeclaredName {
  attribute IdentifierName name;
  attribute AssertedDeclaredKind kind;
  attribute boolean isCaptured;
};

interface AssertedPositionalParameterName {
  attribute unsigned long index;
  attribute IdentifierName name;
  attribute boolean isCaptured;
};

interface AssertedRestParameterName {
  attribute IdentifierName name;
  attribute boolean isCaptured;
};

interface AssertedParameterName {
  attribute IdentifierName name;
  attribute boolean isCaptured;
};

typedef (AssertedPositionalParameterName or
         AssertedRestParameterName or
         AssertedParameterName)
        AssertedMaybePositionalParameterName;

interface AssertedBoundName {
  attribute IdentifierName name;
  attribute boolean isCaptured;
};

interface AssertedBlockScope {
  attribute FrozenArray<AssertedDeclaredName> declaredNames;
  attribute boolean hasDirectEval;
};

interface AssertedScriptGlobalScope {
  attribute FrozenArray<AssertedDeclaredName> declaredNames;
  attribute boolean hasDirectEval;
};

interface AssertedVarScope {
  attribute FrozenArray<AssertedDeclaredName> declaredNames;
  attribute boolean hasDirectEval;
};

interface AssertedParameterScope {
  attribute FrozenArray<AssertedMaybePositionalParameterName> paramNames;
  attribute boolean hasDirectEval;
  attribute boolean isSimpleParameterList;
};

interface AssertedBoundNamesScope {
  attribute FrozenArray<AssertedBoundName> boundNames;
  attribute boolean hasDirectEval;
};

// nodes

interface Node {
  [TypeIndicator] readonly attribute Type type;
};

typedef (Script or Module) Program;

typedef (DoWhileStatement or
         ForInStatement or
         ForOfStatement or
         ForStatement or
         WhileStatement)
        IterationStatement;

typedef (Block or
         BreakStatement or
         ContinueStatement or
         ClassDeclaration or
         DebuggerStatement or
         EmptyStatement or
         ExpressionStatement or
         FunctionDeclaration or
         IfStatement or
         IterationStatement or
         LabelledStatement or
         ReturnStatement or
         SwitchStatement or
         SwitchStatementWithDefault or
         ThrowStatement or
         TryCatchStatement or
         TryFinallyStatement or
         VariableDeclaration or
         WithStatement)
        Statement;

typedef (LiteralBooleanExpression or
         LiteralInfinityExpression or
         LiteralNullExpression or
         LiteralNumericExpression or
         LiteralStringExpression)
        Literal;

typedef (Literal or
         LiteralRegExpExpression or
         ArrayExpression or
         ArrowExpression or
         AssignmentExpression or
         BinaryExpression or
         CallExpression or
         CompoundAssignmentExpression or
         ComputedMemberExpression or
         ConditionalExpression or
         ClassExpression or
         FunctionExpression or
         IdentifierExpression or
         NewExpression or
         NewTargetExpression or
         ObjectExpression or
         UnaryExpression or
         StaticMemberExpression or
         TemplateExpression or
         ThisExpression or
         UpdateExpression or
         YieldExpression or
         YieldStarExpression or
         AwaitExpression)
        Expression;

typedef (ComputedPropertyName or
         LiteralPropertyName)
        PropertyName;

typedef (Method or Getter or Setter) MethodDefinition;

typedef (MethodDefinition or
         DataProperty or
         ShorthandProperty)
        ObjectProperty;

typedef (ExportAllFrom or
         ExportFrom or
         ExportLocals or
         ExportDefault or
         Export)
        ExportDeclaration;

typedef (ImportNamespace or Import) ImportDeclaration;

typedef (EagerFunctionDeclaration or
         LazyFunctionDeclaration) FunctionDeclaration;

typedef (EagerFunctionExpression or
         LazyFunctionExpression) FunctionExpression;

typedef (EagerMethod or LazyMethod) Method;

typedef (EagerGetter or LazyGetter) Getter;

typedef (EagerSetter or LazySetter) Setter;

typedef (EagerArrowExpressionWithFunctionBody or
         LazyArrowExpressionWithFunctionBody or
         EagerArrowExpressionWithExpression or
         LazyArrowExpressionWithExpression) ArrowExpression;

// bindings

interface BindingIdentifier : Node {
  attribute Identifier name;
};

typedef (ObjectBinding or
         ArrayBinding)
        BindingPattern;
typedef (BindingPattern or
         BindingIdentifier)
        Binding;

typedef (AssignmentTargetIdentifier or
         ComputedMemberAssignmentTarget or
         StaticMemberAssignmentTarget)
        SimpleAssignmentTarget;
typedef (ObjectAssignmentTarget or
         ArrayAssignmentTarget)
        AssignmentTargetPattern;
// `DestructuringAssignmentTarget`
typedef (AssignmentTargetPattern or
         SimpleAssignmentTarget)
        AssignmentTarget;

// `FormalParameter`
typedef (Binding or
         BindingWithInitializer)
        Parameter;

interface BindingWithInitializer : Node {
  attribute Binding binding;
  attribute Expression init;
};

interface AssignmentTargetIdentifier : Node {
  attribute Identifier name;
};

interface ComputedMemberAssignmentTarget : Node {
  // The object whose property is being assigned.
  attribute (Expression or Super) _object;
  // The expression resolving to the name of the property to be accessed.
  attribute Expression expression;
};

interface StaticMemberAssignmentTarget : Node {
  // The object whose property is being assigned.
  attribute (Expression or Super) _object;
  // The name of the property to be accessed.
  attribute IdentifierName property;
};

// `ArrayBindingPattern`
interface ArrayBinding : Node {
  // The elements of the array pattern; a null value represents an elision.
  attribute FrozenArray<(Binding or BindingWithInitializer)?> elements;
  attribute Binding? rest;
};

// `SingleNameBinding`
interface BindingPropertyIdentifier : Node {
  attribute BindingIdentifier binding;
  attribute Expression? init;
};

// `BindingProperty :: PropertyName : BindingElement`
interface BindingPropertyProperty : Node {
  attribute PropertyName name;
  attribute (Binding or BindingWithInitializer) binding;
};

typedef (BindingPropertyIdentifier or
         BindingPropertyProperty)
        BindingProperty;

interface ObjectBinding : Node {
  attribute FrozenArray<BindingProperty> properties;
};

// This interface represents the case where the initializer is present in
// `AssignmentElement :: DestructuringAssignmentTarget Initializer_opt`.
interface AssignmentTargetWithInitializer : Node {
  attribute AssignmentTarget binding;
  attribute Expression init;
};

// `ArrayAssignmentPattern`
interface ArrayAssignmentTarget : Node {
  // The elements of the array pattern; a null value represents an elision.
  attribute FrozenArray<(AssignmentTarget or AssignmentTargetWithInitializer?)> elements;
  attribute AssignmentTarget? rest;
};

// `AssignmentProperty :: IdentifierReference Initializer_opt`
interface AssignmentTargetPropertyIdentifier : Node {
  attribute AssignmentTargetIdentifier binding;
  attribute Expression? init;
};

// `AssignmentProperty :: PropertyName : Node`
interface AssignmentTargetPropertyProperty : Node {
  attribute PropertyName name;
  attribute (AssignmentTarget or AssignmentTargetWithInitializer) binding;
};

typedef (AssignmentTargetPropertyIdentifier or
         AssignmentTargetPropertyProperty)
        AssignmentTargetProperty;

// `ObjectAssignmentPattern`
interface ObjectAssignmentTarget : Node {
  attribute FrozenArray<AssignmentTargetProperty> properties;
};


// classes

interface ClassExpression : Node {
  attribute BindingIdentifier? name;
  attribute Expression? super;
  attribute FrozenArray<ClassElement> elements;
};

interface ClassDeclaration : Node {
  attribute BindingIdentifier name;
  attribute Expression? super;
  attribute FrozenArray<ClassElement> elements;
};

interface ClassElement : Node {
  // True iff `IsStatic` of ClassElement is true.
  attribute boolean isStatic;
  attribute MethodDefinition method;
};


// modules

interface Module : Node {
  attribute AssertedVarScope scope;
  attribute FrozenArray<Directive> directives;
  attribute FrozenArray<(ImportDeclaration or ExportDeclaration or Statement)> items;
};

// An `ImportDeclaration` not including a namespace import.
interface Import : Node {
  attribute string moduleSpecifier;
  // `ImportedDefaultBinding`, if present.
  attribute BindingIdentifier? defaultBinding;
  attribute FrozenArray<ImportSpecifier> namedImports;
};

// An `ImportDeclaration` including a namespace import.
interface ImportNamespace : Node {
  attribute string moduleSpecifier;
  // `ImportedDefaultBinding`, if present.
  attribute BindingIdentifier? defaultBinding;
  attribute BindingIdentifier namespaceBinding;
};

interface ImportSpecifier : Node {
  // The `IdentifierName` in the production `ImportSpecifier :: IdentifierName as ImportedBinding`;
  // absent if this specifier represents the production `ImportSpecifier :: ImportedBinding`.
  attribute IdentifierName? name;
  attribute BindingIdentifier binding;
};

// `export * FromClause;`
interface ExportAllFrom : Node {
  attribute string moduleSpecifier;
};

// `export ExportClause FromClause;`
interface ExportFrom : Node {
  attribute FrozenArray<ExportFromSpecifier> namedExports;
  attribute string moduleSpecifier;
};

// `export ExportClause;`
interface ExportLocals : Node {
  attribute FrozenArray<ExportLocalSpecifier> namedExports;
};

// `export VariableStatement`, `export Declaration`
interface Export : Node {
  attribute (FunctionDeclaration or ClassDeclaration or VariableDeclaration) declaration;
};

// `export default HoistableDeclaration`,
// `export default ClassDeclaration`,
// `export default AssignmentExpression`
interface ExportDefault : Node {
  attribute (FunctionDeclaration or ClassDeclaration or Expression) body;
};

// `ExportSpecifier`, as part of an `ExportFrom`.
interface ExportFromSpecifier : Node {
  // The only `IdentifierName in `ExportSpecifier :: IdentifierName`,
  // or the first in `ExportSpecifier :: IdentifierName as IdentifierName`.
  attribute IdentifierName name;
  // The second `IdentifierName` in `ExportSpecifier :: IdentifierName as IdentifierName`,
  // if that is the production represented.
  attribute IdentifierName? exportedName;
};

// `ExportSpecifier`, as part of an `ExportLocals`.
interface ExportLocalSpecifier : Node {
  // The only `IdentifierName in `ExportSpecifier :: IdentifierName`,
  // or the first in `ExportSpecifier :: IdentifierName as IdentifierName`.
  attribute IdentifierExpression name;
  // The second `IdentifierName` in `ExportSpecifier :: IdentifierName as IdentifierName`, if present.
  attribute IdentifierName? exportedName;
};


// property definition

// `MethodDefinition :: PropertyName ( UniqueFormalParameters ) { FunctionBody }`,
// `GeneratorMethod :: * PropertyName ( UniqueFormalParameters ) { GeneratorBody }`,
// `AsyncMethod :: async PropertyName ( UniqueFormalParameters ) { AsyncFunctionBody }`
interface EagerMethod : Node {
  attribute boolean isAsync;
  attribute boolean isGenerator;
  attribute PropertyName name;
  // `length` property of this method.
  attribute unsigned long length;
  attribute FrozenArray<Directive> directives;
  attribute FunctionOrMethodContents contents;
};
interface LazyMethod : Node {
  attribute boolean isAsync;
  attribute boolean isGenerator;
  attribute PropertyName name;
  // `length` property of this method.
  attribute unsigned long length;
  attribute FrozenArray<Directive> directives;
  [Lazy] attribute FunctionOrMethodContents contents;
};

// `get PropertyName ( ) { FunctionBody }`
interface EagerGetter : Node {
  attribute PropertyName name;
  attribute FrozenArray<Directive> directives;
  attribute GetterContents contents;
};
interface LazyGetter : Node {
  attribute PropertyName name;
  attribute FrozenArray<Directive> directives;
  [Lazy] attribute GetterContents contents;
};

interface GetterContents : Node {
  attribute boolean isThisCaptured;
  attribute AssertedVarScope bodyScope;
  attribute FunctionBody body;
};

// `set PropertyName ( PropertySetParameterList ) { FunctionBody }`
interface EagerSetter : Node {
  attribute PropertyName name;
  // `length` property of this setter function.
  attribute unsigned long length;
  attribute FrozenArray<Directive> directives;
  attribute SetterContents contents;
};
interface LazySetter : Node {
  attribute PropertyName name;
  // `length` property of this setter function.
  attribute unsigned long length;
  attribute FrozenArray<Directive> directives;
  [Lazy] attribute SetterContents contents;
};

interface SetterContents : Node {
  attribute boolean isThisCaptured;
  attribute AssertedParameterScope parameterScope;
  attribute Parameter param;
  attribute AssertedVarScope bodyScope;
  attribute FunctionBody body;
};

// `PropertyDefinition :: PropertyName : AssignmentExpression`
interface DataProperty : Node {
  attribute PropertyName name;
  // The `AssignmentExpression`.
  attribute Expression expression;
};

// `PropertyDefinition :: IdentifierReference`
interface ShorthandProperty : Node {
  // The `IdentifierReference`.
  attribute IdentifierExpression name;
};

interface ComputedPropertyName : Node {
  attribute Expression expression;
};

// `LiteralPropertyName`
interface LiteralPropertyName : Node {
  attribute string value;
};


// literals

// `BooleanLiteral`
interface LiteralBooleanExpression : Node {
  attribute boolean value;
};

// A `NumericLiteral` for which the Number value of its MV is positive infinity.
interface LiteralInfinityExpression : Node { };

// `NullLiteral`
interface LiteralNullExpression : Node { };

// `NumericLiteral`
interface LiteralNumericExpression : Node {
  attribute double value;
};

// `RegularExpressionLiteral`
interface LiteralRegExpExpression : Node {
  attribute string pattern;
  attribute string flags;
};

// `StringLiteral`
interface LiteralStringExpression : Node {
  attribute string value;
};


// other expressions

// `ArrayLiteral`
interface ArrayExpression : Node {
  // The elements of the array literal; a null value represents an elision.
  attribute FrozenArray<(SpreadElement or Expression)?> elements;
};

// `ArrowFunction`,
// `AsyncArrowFunction`
interface EagerArrowExpressionWithFunctionBody : Node {
  // True for `AsyncArrowFunction`, false otherwise.
  attribute boolean isAsync;
  // `length` property of this arrow function.
  attribute unsigned long length;
  attribute FrozenArray<Directive> directives;
  attribute ArrowExpressionContentsWithFunctionBody contents;
};
interface LazyArrowExpressionWithFunctionBody : Node {
  // True for `AsyncArrowFunction`, false otherwise.
  attribute boolean isAsync;
  // `length` property of this arrow function.
  attribute unsigned long length;
  attribute FrozenArray<Directive> directives;
  [Lazy] attribute ArrowExpressionContentsWithFunctionBody contents;
};
interface EagerArrowExpressionWithExpression : Node {
  // True for `AsyncArrowFunction`, false otherwise.
  attribute boolean isAsync;
  // `length` property of this arrow function.
  attribute unsigned long length;
  attribute ArrowExpressionContentsWithExpression contents;
};
interface LazyArrowExpressionWithExpression : Node {
  // True for `AsyncArrowFunction`, false otherwise.
  attribute boolean isAsync;
  // `length` property of this arrow function.
  attribute unsigned long length;
  [Lazy] attribute ArrowExpressionContentsWithExpression contents;
};

interface ArrowExpressionContentsWithFunctionBody : Node {
  attribute AssertedParameterScope parameterScope;
  attribute FormalParameters params;
  attribute AssertedVarScope bodyScope;
  attribute FunctionBody body;
};

interface ArrowExpressionContentsWithExpression : Node {
  attribute AssertedParameterScope parameterScope;
  attribute FormalParameters params;
  attribute AssertedVarScope bodyScope;
  attribute Expression body;
};

// `AssignmentExpression :: LeftHandSideExpression = AssignmentExpression`
interface AssignmentExpression : Node {
  // The `LeftHandSideExpression`.
  attribute AssignmentTarget binding;
  // The `AssignmentExpression` following the `=`.
  attribute Expression expression;
};

// `ExponentiationExpression`,
// `MultiplicativeExpression`,
// `AdditiveExpression`,
// `ShiftExpression`,
// `RelationalExpression`,
// `EqualityExpression`,
// `BitwiseANDExpression`,
// `BitwiseXORExpression`,
// `BitwiseORExpression`,
// `LogicalANDExpression`,
// `LogicalORExpression`
interface BinaryExpression : Node {
  attribute BinaryOperator operator;
  // The expression before the operator.
  attribute Expression left;
  // The expression after the operator.
  attribute Expression right;
};

interface CallExpression : Node {
  attribute (Expression or Super) callee;
  attribute Arguments arguments;
};

// `AssignmentExpression :: LeftHandSideExpression AssignmentOperator AssignmentExpression`
interface CompoundAssignmentExpression : Node {
  attribute CompoundAssignmentOperator operator;
  // The `LeftHandSideExpression`.
  attribute SimpleAssignmentTarget binding;
  // The `AssignmentExpression`.
  attribute Expression expression;
};

interface ComputedMemberExpression : Node {
  // The object whose property is being accessed.
  attribute (Expression or Super) _object;
  // The expression resolving to the name of the property to be accessed.
  attribute Expression expression;
};

// `ConditionalExpression :: LogicalORExpression ? AssignmentExpression : AssignmentExpression`
interface ConditionalExpression : Node {
  // The `LogicalORExpression`.
  attribute Expression test;
  // The first `AssignmentExpression`.
  attribute Expression consequent;
  // The second `AssignmentExpression`.
  attribute Expression alternate;
};

// `FunctionExpression`,
// `GeneratorExpression`,
// `AsyncFunctionExpression`,
interface EagerFunctionExpression : Node {
  attribute boolean isAsync;
  attribute boolean isGenerator;
  attribute BindingIdentifier? name;
  // `length` property of this function.
  attribute unsigned long length;
  attribute FrozenArray<Directive> directives;
  attribute FunctionExpressionContents contents;
};
interface LazyFunctionExpression : Node {
  attribute boolean isAsync;
  attribute boolean isGenerator;
  attribute BindingIdentifier? name;
  // `length` property of this function.
  attribute unsigned long length;
  attribute FrozenArray<Directive> directives;
  [Lazy] attribute FunctionExpressionContents contents;
};

interface FunctionExpressionContents : Node {
  attribute boolean isFunctionNameCaptured;
  attribute boolean isThisCaptured;
  attribute AssertedParameterScope parameterScope;
  attribute FormalParameters params;
  attribute AssertedVarScope bodyScope;
  attribute FunctionBody body;
};

// `IdentifierReference`
interface IdentifierExpression : Node {
  attribute Identifier name;
};

interface NewExpression : Node {
  attribute Expression callee;
  attribute Arguments arguments;
};

interface NewTargetExpression : Node { };

interface ObjectExpression : Node {
  attribute FrozenArray<ObjectProperty> properties;
};

interface UnaryExpression : Node {
  attribute UnaryOperator operator;
  attribute Expression operand;
};

interface StaticMemberExpression : Node {
  // The object whose property is being accessed.
  attribute (Expression or Super) _object;
  // The name of the property to be accessed.
  attribute IdentifierName property;
};

// `TemplateLiteral`,
// `MemberExpression :: MemberExpression TemplateLiteral`,
// `CallExpression : CallExpression TemplateLiteral`
interface TemplateExpression : Node {
  // The second `MemberExpression` or `CallExpression`, if present.
  attribute Expression? tag;
  // The contents of the template. This list must be alternating
  // TemplateElements and Expressions, beginning and ending with
  // TemplateElement.
  attribute FrozenArray<(Expression or TemplateElement)> elements;
};

// `PrimaryExpression :: this`
interface ThisExpression : Node { };

// `UpdateExpression :: LeftHandSideExpression ++`,
// `UpdateExpression :: LeftHandSideExpression --`,
// `UpdateExpression :: ++ LeftHandSideExpression`,
// `UpdateExpression :: -- LeftHandSideExpression`
interface UpdateExpression : Node {
  // True for `UpdateExpression :: ++ LeftHandSideExpression` and
  // `UpdateExpression :: -- LeftHandSideExpression`, false otherwise.
  attribute boolean isPrefix;
  attribute UpdateOperator operator;
  attribute SimpleAssignmentTarget operand;
};

// `YieldExpression :: yield`,
// `YieldExpression :: yield AssignmentExpression`
interface YieldExpression : Node {
  // The `AssignmentExpression`, if present.
  attribute Expression? expression;
};

// `YieldExpression :: yield * AssignmentExpression`
interface YieldStarExpression : Node {
  attribute Expression expression;
};

interface AwaitExpression : Node {
  attribute Expression expression;
};


// other statements

interface BreakStatement : Node {
  attribute Label? label;
};

interface ContinueStatement : Node {
  attribute Label? label;
};

interface DebuggerStatement : Node { };

interface DoWhileStatement : Node {
  attribute Expression test;
  attribute Statement body;
};

interface EmptyStatement : Node { };

interface ExpressionStatement : Node {
  attribute Expression expression;
};

interface ForInOfBinding : Node {
  attribute VariableDeclarationKind kind;
  attribute Binding binding;
};

// `for ( LeftHandSideExpression in Expression ) Statement`,
// `for ( var ForBinding in Expression ) Statement`,
// `for ( ForDeclaration in Expression ) Statement`,
// `for ( var BindingIdentifier Initializer in Expression ) Statement`
interface ForInStatement : Node {
  // The expression or declaration before `in`.
  attribute (ForInOfBinding or AssignmentTarget) left;
  // The expression after `in`.
  attribute Expression right;
  attribute Statement body;
};

// `for ( LeftHandSideExpression of Expression ) Statement`,
// `for ( var ForBinding of Expression ) Statement`,
// `for ( ForDeclaration of Expression ) Statement`
interface ForOfStatement : Node {
  // The expression or declaration before `of`.
  attribute (ForInOfBinding or AssignmentTarget) left;
  // The expression after `of`.
  attribute Expression right;
  attribute Statement body;
};

// `for ( Expression ; Expression ; Expression ) Statement`,
// `for ( var VariableDeclarationList ; Expression ; Expression ) Statement`
interface ForStatement : Node {
  // The expression or declaration before the first `;`, if present.
  attribute (VariableDeclaration or Expression)? init;
  // The expression before the second `;`, if present
  attribute Expression? test;
  // The expression after the second `;`, if present
  attribute Expression? update;
  attribute Statement body;
};

// `if ( Expression ) Statement`,
// `if ( Expression ) Statement else Statement`,
interface IfStatement : Node {
  attribute Expression test;
  // The first `Statement`.
  attribute Statement consequent;
  // The second `Statement`, if present.
  attribute Statement? alternate;
};

interface LabelledStatement : Node {
  attribute Label label;
  attribute Statement body;
};

interface ReturnStatement : Node {
  attribute Expression? expression;
};

// A `SwitchStatement` whose `CaseBlock` is
//   `CaseBlock :: { CaseClauses }`.
interface SwitchStatement : Node {
  attribute Expression discriminant;
  attribute FrozenArray<SwitchCase> cases;
};

// A `SwitchStatement` whose `CaseBlock` is
//   `CaseBlock :: { CaseClauses DefaultClause CaseClauses }`.
interface SwitchStatementWithDefault : Node {
  attribute Expression discriminant;
  // The `CaseClauses` before the `DefaultClause`.
  attribute FrozenArray<SwitchCase> preDefaultCases;
  // The `DefaultClause`.
  attribute SwitchDefault defaultCase;
  // The `CaseClauses` after the `DefaultClause`.
  attribute FrozenArray<SwitchCase> postDefaultCases;
};

interface ThrowStatement : Node {
  attribute Expression expression;
};

// `TryStatement :: try Block Catch`
interface TryCatchStatement : Node {
  attribute Block body;
  attribute CatchClause catchClause;
};

// `TryStatement :: try Block Finally`,
// `TryStatement :: try Block Catch Finally`
interface TryFinallyStatement : Node {
  // The `Block`.
  attribute Block body;
  // The `Catch`, if present.
  attribute CatchClause? catchClause;
  // The `Finally`.
  attribute Block finalizer;
};

interface WhileStatement : Node {
  attribute Expression test;
  attribute Statement body;
};

interface WithStatement : Node {
  attribute Expression _object;
  attribute Statement body;
};


// other nodes

interface Block : Node {
  attribute AssertedBlockScope scope;
  attribute FrozenArray<Statement> statements;
};

// `Catch`
interface CatchClause : Node {
  attribute AssertedBoundNamesScope bindingScope;
  attribute Binding binding;
  attribute Block body;
};

// An item in a `DirectivePrologue`
interface Directive : Node {
  attribute string rawValue;
};

interface FormalParameters : Node {
  attribute FrozenArray<Parameter> items;
  attribute Binding? rest;
};

typedef FrozenArray<Statement> FunctionBody;



// `FunctionDeclaration`,
// `GeneratorDeclaration`,
// `AsyncFunctionDeclaration`
interface EagerFunctionDeclaration : Node {
  attribute boolean isAsync;
  attribute boolean isGenerator;
  attribute BindingIdentifier name;
  // `length` property of this function.
  attribute unsigned long length;
  attribute FrozenArray<Directive> directives;
  attribute FunctionOrMethodContents contents;
};

interface LazyFunctionDeclaration : Node {
  attribute boolean isAsync;
  attribute boolean isGenerator;
  attribute BindingIdentifier name;
  // `length` property of this function.
  attribute unsigned long length;
  attribute FrozenArray<Directive> directives;
  [Lazy] attribute FunctionOrMethodContents contents;
};

interface FunctionOrMethodContents : Node {
  attribute boolean isThisCaptured;
  attribute AssertedParameterScope parameterScope;
  attribute FormalParameters params;
  attribute AssertedVarScope bodyScope;
  attribute FunctionBody body;
};


interface Script : Node {
  attribute AssertedScriptGlobalScope scope;
  attribute FrozenArray<Directive> directives;
  attribute FrozenArray<Statement> statements;
};

interface SpreadElement : Node {
  attribute Expression expression;
};

// `super`
interface Super : Node { };

// `CaseClause`
interface SwitchCase : Node {
  attribute Expression test;
  attribute FrozenArray<Statement> consequent;
};

// `DefaultClause`
interface SwitchDefault : Node {
  attribute FrozenArray<Statement> consequent;
};

// `TemplateCharacters`
interface TemplateElement : Node {
  attribute string rawValue;
};

interface VariableDeclaration : Node {
  attribute VariableDeclarationKind kind;
  [NonEmpty] attribute FrozenArray<VariableDeclarator> declarators;
};

interface VariableDeclarator : Node {
  attribute Binding binding;
  attribute Expression? init;
};

2Transformation of AST to Parse Tree

The Ecmaify abstract operation transforms binary AST Nodes to ECMAScript Parse Nodes. It performs additional early error checking on top of existing ECMAScript early error semantics.

A Parse Node may be tagged as being transformed by a binary AST Node with an optional asserted scope. The original binary AST Node and the optional asserted scope are retrievable from tagged Parse Nodes.

Note
Tagging Parse Nodes is used to introduce laziness at function body boundaries.

The current asserted scope is used to track asserted scopes during transformation of binary AST Nodes.

The naming convention of the Ecmaify abstract operations is:

2.1StatementEcmaify ( stmt )

  1. Assert: stmt is a Statement.
  2. Let n be ? Ecmaify(stmt).
  3. If stmt is a Block, then
    1. Set n to BlockStatement : n.
  4. Else if stmt is an IterationStatement, then
    1. Set n to BreakableStatement : n.
  5. Else return Statement : n.

2.2StatementListEcmaify ( stmts )

  1. Assert: stmts is a FrozenArray<Statement>.
  2. Let list be an empty Parse Node.
  3. If stmts has length 0, then
    1. Let emptyStmt be StatementListItem : EmptyStatement.
    2. Set list to StatementList : emptyStmt.
  4. For each stmt in stmts, do
    1. If stmt is a FunctionDeclaration, then
      1. Set n to HoistableDeclaration: ? Ecmaify(stmt).
      2. Set n to be Declaration : n.
    2. Else if stmt an ExpressionStatement and stmt.expression is a LiteralStringExpression:
      1. NOTE: String literals expression statements are always parenthsized to avoid being interpreted as directives.
      2. Set n to be ExpressionEcmaify(stmt.expression).
      3. Set n to be PrimaryExpression : ( n /.
      4. Set n to be MemberExpression : n.
      5. Set n to be NewExpression : n.
      6. Set n to be LeftHandSideExpression : n.
      7. Set n to be UpdateExpression : n.
      8. Set n to be UnaryExpression : n.
      9. Set n to be ExponentiationExpression : n.
      10. Set n to be MultiplicativeExpression : n.
      11. Set n to be AdditiveExpression : n.
      12. Set n to be ShiftExpression : n.
      13. Set n to be RelationalExpression : n.
      14. Set n to be EqualityExpression : n.
      15. Set n to be BitwiseANDExpression : n.
      16. Set n to be BitwiseXORExpression : n.
      17. Set n to be BitwiseORExpression : n.
      18. Set n to be LogicalANDExpression : n.
      19. Set n to be LogicalORExpression : n.
      20. Set n to be AssignmentExpression : n.
      21. Set n to be Expression : n.
      22. Set n to be ExpressionStatement : n ;.
    3. Else set n to be ? StatementEcmaify(stmt).
    4. Set n to be StatementListItem : n.
    5. If list is empty, then set list to StatementList : n.
    6. Else set list to StatementList : list n.
  5. Return list.

2.3VariableDeclarationListEcmaify ( decls )

  1. Assert: decls is a FrozenArray<VariableDeclarator>.
  2. Assert: decls does not have length 0.
  3. Let list be an empty Parse Node.
  4. For each decl in decls, do
    1. Let n be an empty Parse Node.
    2. Let binding be ? Ecmaify(decl.binding).
    3. If decl.init is null, then
      1. If decl.binding is not a BindingIdentifier, throw a SyntaxError exception.
      2. Set n to VariableDeclaration : binding.
    4. Else,
      1. Let init be ? Ecmaify(decl.init).
      2. Set n to VariableDeclaration : binding init.
    5. If list is empty, set list to VariableDeclarationList : n.
    6. Else set list to VariableDeclarationList : list n.
  5. Return list.

2.4BindingListEcmaify ( decls )

  1. Assert: decls is a FrozenArray<VariableDeclarator>.
  2. Assert: decls does not have length 0.
  3. Let list be an empty Parse Node.
  4. For each decl in decls, do
    1. Let n be an empty Parse Node.
    2. Let binding be ? Ecmaify(decl.binding).
    3. If decl.init is null, then
      1. If decl.binding is not a BindingIdentifier, throw a SyntaxError exception.
      2. Set n to LexicalBinding : binding.
    4. Else,
      1. Let init be ? Ecmaify(decl.init).
      2. Set n to LexicalBinding : binding init.
    5. If list is empty, set list to BindingList : n.
    6. Else set list to BindingList : list n.
  5. Return list.

2.5ElementListEcmaify ( elems )

  1. Assert: elems is a FrozenArray<SpreadElement or Expression>.
  2. Assert: elems does not have length 0.
  3. Let list be an empty Parse Node.
  4. Let accumulatedElisions be an empty Parse Node.
  5. For each elem in elems, do
    1. Let n be an empty Parse Node.
    2. If elem is null, then
      1. If accumulatedElisions is empty, then set accumulatedElisions to Elision : ,.
      2. Else set accumulatedElisions to Elision : accumulatedElisions ,.
    3. Else,
      1. If elem is a SpreadElement, then
        1. Let expr be ? AssigmentExpressionEcmaify(elem.expression).
        2. Set n to SpreadElement : ... expr.
      2. Else set n to ? AssignmentExpressionEcmaify(elem).
      3. If list is empty, then
        1. If accumulatedElisions is empty, then set list to ElementList : n.
        2. Else set list to ElementList : accumulatedElisions n.
      4. Else,
        1. If accumulatedElisions is empty, then set list to ElementList : list , n.
        2. Else set list to ElementList : list , accumulatedElisions n.
      5. Set accumulatedElisions to an empty Parse Node.
  6. Return list and accumulatedElisions.

2.6FormalParameterListEcmaify ( params )

  1. Assert: params is a FrozenArray<Parameter>.
  2. Assert: params does not have length 0.
  3. Let list be an empty Parse Node.
  4. For each param in params, do
    1. Let n be ? Ecmaify(param).
    2. If list is empty, then set list to FormalParameterList : n.
    3. Else set list to FormalParameterList : list , n.
  5. Return list.

2.7ArgumentListEcmaify ( args )

  1. Assert: args is an Arguments.
  2. Assert: args does not have length 0.
  3. Let list be an empty Parse Node.
  4. For each arg in args, do
    1. If arg is a SpreadElement, then
      1. Let expr be ? AssignmentExpressionEcmaify(arg.expression).
      2. If list is empty, then set list to ArgumentList : ... expr.
      3. Else set list to ArgumentList : list , expr.
    2. Else,
      1. Let expr be ? AssignmentExpressionEcmaify(arg).
      2. If list is empty, then set list to ArgumentList : expr.
      3. Else set list to ArgumentList : list , expr.
  5. Return list.

2.8PropertyDefinitionListEcmaify ( props )

  1. Assert: props is a FrozenArray<ObjectProperty> or a `FrozenArray<AssignmentTargetProperty>.
  2. Assert: props does not have length 0.
  3. Let list be an empty Parse Node.
  4. For each prop in props, do
    1. If prop is a MethodDefinition, then let n be PropertyDefinition : ? Ecmaify(prop).
    2. Else let n be ? Ecmaify(prop).
    3. If list is empty, then set list to PropertyDefinitionList : n.
    4. Else set list to PropertyDefinitionList : list , n.
  5. Return list.

2.9CaseClauseEcmaify ( case )

  1. Assert: case is a SwitchCase.
  2. Let expr be ? ExpressionEcmaify(case.test).
  3. Let clause be an empty Parse Node.
  4. If case.consequent has length 0, then
    1. Set clause to CaseClause : case expr :.
  5. Else,
    1. Let stmts be ? StatementListEcmaify(case.consequent).
    2. Set clause to CaseClause : case expr : stmts.
  6. Return clause.

2.10DefaultClauseEcmaify ( case )

  1. Assert: case is a SwitchDefault.
  2. Let clause be an empty Parse Node.
  3. If case.consequent has length 0, then
    1. Set clause to CaseClause : default :.
  4. Else,
    1. Let stmts be ? StatementListEcmaify(case.consequent).
    2. Set clause to CaseClause : default : stmts.
  5. Return clause.

2.11CaseClausesEcmaify ( cases )

  1. Assert: cases is a FrozenArray<SwitchCase>.
  2. Assert: cases does not have length 0.
  3. Let clauses be an empty Parse Node.
  4. For case in cases:
    1. Let clause be ? CaseClauseEcmaify(case).
    2. If clauses is empty, then set clauses to CaseClauses : clause.
    3. Else set clauses to CaseClauses : clauses clause.
  5. Return clauses.

2.12ArgumentsEcmaify ( args )

  1. Assert: args is an Arguments.
  2. If args has length 0, then return Arguments : ( ).
  3. Else,
    1. Let list be ? ArgumentListEcmaify(call.arguments).
    2. Return Arguments : ( list ).

2.13PrimaryExpressionEcmaify ( e )

  1. Assert: e is an Expression, an AssignmentTarget, or an AssignmentTargetWithInitializer.
  2. If e is a ThisExpression, then return ? Ecmaify(e).
  3. Else if pn is an IdentifierExpression, a Literal, an ArrayExpression, an ObjectExpression, a FunctionExpression, a ClassExpression, a LiteralRegExpExpression, a TemplateExpression, an AssignmentTargetIdentifier, an ArrayAssignmentExpression, or an ObjectAssignmentExpression, then return PrimaryExpression : ? Ecmaify(e).
  4. Else,
    1. Let parenthesized be ParenthesizedExpression : (ExpressionEcmaify(e) ).
    2. Return PrimaryExpression : parenthesized.

2.14MemberExpressionEcmaify ( e )

  1. Assert: e is an Expression, an AssignmentTarget, or an AssignmentTargetWithInitializer.
  2. If e is a ComputedMemberExpression, a StaticMemberExpression, a NewTargetExpression, a NewExpression, a ComputedMemberAssignmentTarget, or a StaticMemberAssignmentTarget, then return ? Ecmaify(e).
  3. Else,
    1. Let n be ? PrimaryExpressionEcmaify(e).
    2. Return MemberExpression : n.

2.15LeftHandSideExpressionEcmaify ( e )

  1. Assert: e is an Expression, an AssignmentTarget, or an AssignmentTargetWithInitializer.
  2. If e is a NewExpression, then
    1. Let n be NewExpression : ? Ecmaify(e).
    2. Return LeftHandSideExpression : n.
  3. Else if e is a CallExpression, then return LeftHandExpression : ? Ecmaify(e).
  4. Else,
    1. Let n be NewExpression : ? MemberExpressionEcmaify(e).
    2. Return LeftHandSideExpression: n.

2.16UpdateExpressionEcmaify ( e )

  1. Assert: e is an Expression, an AssignmentTarget, or an AssignmentTargetWithInitializer.
  2. If e is an UpdateExpression, then return ? Ecmaify(e).
  3. Else,
    1. Let n be ? LeftHandSideExpressionEcmaify(e).
    2. Return UpdateExpression : n.

2.17UnaryExpressionEcmaify ( e )

  1. Assert: e is an Expression, an AssignmentTarget, or an AssignmentTargetWithInitializer.
  2. If e is a UnaryExpression, then return ? Ecmaify(e).
  3. Else if e is an AwaitExpression, then
    1. Let n be ? Ecmaify(e).
    2. Return UnaryExpression : n.
  4. Else,
    1. Let n be ? UpdateExpressionEcmaify(e).
    2. Return UnaryExpresison : n.

2.18ExponentiationExpressionEcmaify ( e )

  1. Assert: e is an Expression, an AssignmentTarget, or an AssignmentTargetWithInitializer.
  2. If e is a BinaryExpression and e.operator is "||", then return ? Ecmaify(e).
  3. Else,
    1. Let n be ? UnaryExpressionEcmaify(e).
    2. Return ExponentiationExpression : n.

2.19MultiplicativeExpressionEcmaify ( e )

  1. Assert: e is an Expression, an AssignmentTarget, or an AssignmentTargetWithInitializer.
  2. If e is a BinaryExpression and e.operator is "|", "/", or "%", then return ? Ecmaify(e).
  3. Else,
    1. Let n be ? ExponentiationExpressionEcmaify(e).
    2. Return MultiplicativeExpression : n.

2.20AdditiveExpressionEcmaify ( e )

  1. Assert: e is an Expression, an AssignmentTarget, or an AssignmentTargetWithInitializer.
  2. If e is a BinaryExpression and e.operator is "+" or "-", then return ? Ecmaify(e).
  3. Else,
    1. Let n be ? MultiplicativeExpressionEcmaify(e).
    2. Return AdditiveExpression : n.

2.21ShiftExpressionEcmaify ( e )

  1. Assert: e is an Expression, an AssignmentTarget, or an AssignmentTargetWithInitializer.
  2. If e is a BinaryExpression and e.operator is "<<", ">>", or ">>>", then return ? Ecmaify(e).
  3. Else,
    1. Let n be ? AdditiveExpressionEcmaify(e).
    2. Return ShiftExpression : n.

2.22RelationalExpressionEcmaify ( e )

  1. Assert: e is an Expression, an AssignmentTarget, or an AssignmentTargetWithInitializer.
  2. If e is a BinaryExpression and e.operator is "<", ">", "<=", ">=", "instanceof", or "in", then return ? Ecmaify(e).
  3. Else,
    1. Let n be ? ShiftExpressionEcmaify(e).
    2. Return RelationalExpression : n.

2.23EqualityExpressionEcmaify ( e )

  1. Assert: e is an Expression, an AssignmentTarget, or an AssignmentTargetWithInitializer.
  2. If e is a BinaryExpression and e.operator is "==", "!=", "===", or "!==", then return ? Ecmaify(e).
  3. Else,
    1. Let n be ? RelationalExpressionEcmaify(e).
    2. Return EqualityExpression : n.

2.24BitwiseANDExpressionEcmaify ( e )

  1. Assert: e is an Expression, an AssignmentTarget, or an AssignmentTargetWithInitializer.
  2. If e is a BinaryExpression and e.operator is "&", then return ? Ecmaify(e).
  3. Else,
    1. Let n be ? EqualityExpressionEcmaify(e).
    2. Return BitwiseANDExpression : n.

2.25BitwiseXORExpressionEcmaify ( e )

  1. Assert: e is an Expression, an AssignmentTarget, or an AssignmentTargetWithInitializer.
  2. If e is a BinaryExpression and e.operator is "^", then return ? Ecmaify(e).
  3. Else,
    1. Let n be ? BitwiseANDExpressionEcmaify(e).
    2. Return BitwiseXORExpression : n.

2.26BitwiseORExpressionEcmaify ( e )

  1. Assert: e is an Expression, an AssignmentTarget, or an AssignmentTargetWithInitializer.
  2. If e is a BinaryExpression and e.operator is "|", then return ? Ecmaify(e).
  3. Else,
    1. Let n be ? BitwiseXORExpressionEcmaify(e).
    2. Return BitwiseORExpression : n.

2.27LogicalANDExpressionEcmaify ( e )

  1. Assert: e is an Expression, an AssignmentTarget, or an AssignmentTargetWithInitializer.
  2. If e is a BinaryExpression and e.operator is "&&", then return ? Ecmaify(e).
  3. Else,
    1. Let n be ? BitwiseORExpressionEcmaify(e).
    2. Return LogicalANDExpression : n.

2.28LogicalORExpressionEcmaify ( e )

  1. Assert: e is an Expression, an AssignmentTarget, or an AssignmentTargetWithInitializer.
  2. If e is a BinaryExpression and e.operator is "||", then return ? Ecmaify(e).
  3. Else,
    1. Let n be ? LogicalANDExpressionEcmaify(e).
    2. Return LogicalORExpression : n.

2.29ConditionalExpressionEcmaify ( e )

  1. Assert: e is an Expression, an AssignmentTarget, or an AssignmentTargetWithInitializer.
  2. If e is a ConditionalExpression, then return ? Ecmaify(e).
  3. Else,
    1. Let n be ? LogicalORExpressionEcmaify(e).
    2. Return ConditionalExpression : n.

2.30AssignmentExpressionEcmaify ( e )

  1. Assert: e is an Expression, an AssignmentTarget, or an AssignmentTargetWithInitializer.
  2. If e is an AssignmentExpression, a CompoundAssignmentExpression, or an AssignmentTargetWithInitializer, then return ? Ecmaify(e).
  3. Else if e is a YieldExpression or an ArrowExpression, then return AssignmentExpression : ? Ecmaify(e).
  4. Else,
    1. Let n be ? ConditionalExpressionEcmaify(e).
    2. Return AssignmentExpression : n.

2.31ExpressionEcmaify ( e )

  1. Assert: e is an Expression, an AssignmentTarget, or an AssignmentTargetWithInitializer.
  2. If e is a BinaryExpression and e.operator is ",", then return ? Ecmaify(e).
  3. Else,
    1. Let n be ? AssignmentExpressionEcmaify(e).
    2. Return Expression : n.

2.32MaybeSynthesizeThisScope ( maybeLazyNode )

  1. If maybeLazyNode is a LazyFunctionDeclaration, a LazyFunctionExpression, a LazyMethod, a LazyGetter, a LazySetter, or a LazyArrowExpression, then return.
  2. Let enclosingScope be the current asserted scope.
  3. Set the current asserted scope to SynthesizeThisScope(maybeLazyNode, enclosingScope).

2.33MaybeSynthesizeNamedLambdaScope ( maybeLazyNode )

  1. If maybeLazyNode is a LazyFunctionExpression, then return.
  2. If maybeLazyNode.contents.isFunctionNameCaptured is false, then return.
  3. Let enclosingScope be the current asserted scope.
  4. Set the current asserted scope to SynthesizeNamedLambdaScope(maybeLazyNode, enclosingScope).

2.34LazyFormalParametersEcmaify ( maybeLazyNode )

  1. NOTE: When a FormalParameters : [empty] tagged as being produced by a binary AST FormalParameters is evaluated at runtime, Ecmaify is run on the parameters at that time to delazify.
  2. If maybeLazyNode is a LazyFunctionDeclaration, a LazyFunctionExpression, or a LazyMethod, then
    1. Let emptyParams be FormalParameters : [empty].
    2. Tag emptyParams as being produced by maybeLazyNode.
    3. Return emptyParams.
  3. Else,
    1. Let enclosingScope be the current asserted scope.
    2. Let params be maybeLazyNode.contents.params.
    3. Let paramScope be maybeLazyNode.contents.parameterScope.
    4. Assert: params is a FormalParameters.
    5. Set the current asserted scope to paramScope.
    6. Perform AddAssertedScopeTreeNode(paramScope, enclosingScope).
    7. Let delazifiedParams be ? EcmaifyFormalParameters(params).
    8. Perform ? CheckFunctionLength(delazifiedParams, maybeLazyNode).
    9. Perform ? CheckAssertedScope(paramScope, delazifiedParams).
    10. Return delazifiedParams.

2.35LazyCoverArrowParameterListEcmaify ( maybeLazyNode )

  1. NOTE: When a CoverParenthesizedExpressionAndArrowParameterList : ( ) tagged as being produced by a binary AST FormalParameters is evaluated at runtime, Ecmaify is run on the parameters at that time to delazify.
  2. If maybeLazyNode is a LazyArrowExpression, then
    1. Let emptyArrowParams0 be a CoverParenthesizedExpressionAndArrowParameterList : ( ).
    2. Let emptyArrowParams be ArrowParameters : emptyArrowParams0.
    3. Tag emptyArrowParams as being produced by maybeLazyNode.
    4. Return emptyArrowParams.
  3. Else,
    1. Let params be maybeLazyNode.content.params.
    2. Let paramScope be maybeLazyNode.content.parameterScope.
    3. Assert: params is a FormalParameters.
    4. Let enclosingScope be the current asserted scope.
    5. Set the current asserted scope to paramScope.
    6. Perform AddAssertedScopeTreeNode(paramScope, enclosingScope).
    7. Let delazifiedParams be ? EcmaifyCoverArrowParameterList(params).
    8. Perform ? CheckFunctionLength(delazifiedParams, maybeLazyNode).
    9. Perform ? CheckAssertedScope(paramScope, delazifiedParams).
    10. Perform ? CheckThisCapture(paramScope, delazifiedParams).
    11. Return delazifiedParams.

2.36LazyPropertySetParameterListEcmaify ( maybeLazyNode )

  1. NOTE: When a PropertySetParameterList tagged as being produced by a binary AST Parameter is evaluated at runtime, Ecmaify is run on the parameter at that time to delazify.
  2. TODO: FormalParameter needs an empty variant for tagging.
  3. If maybeLazyNode is a LazySetter, then
    1. Let placeholder be Identifier : _.
    2. Let emptyPropSetParam0 be FormalParameter : placeholder.
    3. Let emptyPropSetParam be PropertySetParameterList : emptyPropSetParam0.
    4. Let currentScope be the current asserted scope.
    5. Tag emptyPropSetParam as being produced by maybeLazyNode.
    6. Return emptyPropSetParam.
  4. Else,
    1. Let param be maybeLazyNode.contents.param.
    2. Let paramScope be maybeLazyNode.contents.parameterScope.
    3. Assert: param is a Parameter.
    4. Let enclosingScope be the current asserted scope.
    5. Set the current asserted scope to paramScope.
    6. Perform AddAssertedScopeTreeNode(paramScope, enclosingScope).
    7. Let delazifiedParams be ? EcmaifyPropertySetParameterList(param).
    8. Perform ? CheckAssertedScope(paramScope, delazifiedParams).
    9. Return delazifiedParams.

2.37LazyFunctionBodyEcmaify ( maybeLazyNode )

  1. NOTE: When a FunctionBody tagged as being produced by a binary AST is evaluated at runtime, Ecmaify is run on the function at that time to delazify.
  2. If maybeLazyNode is a LazyFunctionDeclaration, a LazyFunctionExpression, a LazyMethod, a LazyGetter, a LazySetter, or a LazyArrowExpression, then
    1. Let emptyStmt be StatementListItem : EmptyStatement.
    2. Let stmts be StatementList : emptyStmt.
    3. Let funcStmts be FunctionStatementList : stmts.
    4. Let body be FunctionBody : funcStmts.
    5. Let currentScope be the current asserted scope.
    6. Tag body as being produced by maybeLazyNode in scope currentScope.
    7. Return body.
  3. Else,
    1. Let enclosingScope be the current asserted scope.
    2. Let contents be maybeLazyNode.contents.
    3. Let bodyScope be contents.bodyScope.
    4. Set the current asserted scope to bodyScope.
    5. Perform AddAssertedScopeTreeNode(bodyScope, enclosingScope).
    6. Let delazifiedBody be ? EcmaifyFunctionBody(funcNode).
    7. Perform ? CheckAssertedScope(bodyScope, delazifiedBody).
    8. If contents is an ArrowExpressionContents, then perform ? CheckThisCapture(bodyScope, delazifiedBody).
    9. Return FunctionBody : delazifiedBody.

2.38IdentifierEcmaify ( ident )

  1. Assert: ident is an Identifier or an IdentifierName.
  2. NOTE: The full tree of identifiers is elided here and left as an exercise to the reader.
  3. If ident is the empty string, throw a SyntaxError exception.
  4. Return Identifier : ident.

2.39LabelIdentifierEcmaify ( l )

  1. Assert: l is a Label.
  2. If l is "yield", then return LabelIdentifier : yield.
  3. Else if l is "await", then return LabelIdentifier : await.
  4. Else return LabelIdentifier : ? IdentifierEcmaify(l).

2.40InitializerEcmaify ( e )

  1. Assert: e is an Expression.
  2. Return Initializer : =AssignmentExpressionEcmaify(e).

2.41BindingPropertyListEcmaify ( props )

  1. Assert: props is a FrozenArray<BindingProperty>.
  2. Assert: props does not have length 0.
  3. Let list be an empty Parse Node.
  4. For each prop in props, do
    1. Let bindingProp be ? Ecmaify(binding).
    2. If list is empty, set list to BindingPropertyList : bindingProp.
    3. Else set list to BindingPropertyList : list , bindingProp.

2.42BindingElementListEcmaify ( elems )

  1. Assert: elems is a FrozenArray<(Binding or BindingWithInitializer)>.
  2. Assert: elems does not have length 0.
  3. Let list be an empty Parse Node.
  4. Let accumulatedElisions be an empty Parse Node.
  5. For each elem in elems, do
    1. Let bindingElem be an empty Parse Node.
    2. If elem is null, then
      1. If accumulatedElisions is empty, then set accumulatedElisions to Elision : ,.
      2. Else set accumulatedElisions to Elision : accumulatedElisions ,.
    3. Else,
      1. Let bindingElem be BindingElisionElement : accumulatedElisionsBindingElementEcmaify(elem).
      2. If list is empty, then set list to BindingElementList : bindingElem.
      3. Else set list to BindingElementList : list , bindingElem.
      4. Set accumulatedElisions to an empty Parse Node.
  6. Return list and accumulatedElisions.

2.43BindingElementEcmaify ( binding )

  1. Assert: binding is a Binding or BindingWithInitializer.
  2. Let elem0 be ? Ecmaify(binding).
  3. If binding is a BindingWithInitializer, then return elem0.
  4. Else,
    1. If binding is a BindingIdentifier, then
      1. Let singleNameBinding be SingleNameBinding : elem0.
      2. Return BindingElement : singleNameBinding.
    2. Else,
      1. Let bindingPattern be BindingPattern : elem0.
      2. Return BindingElement : bindingPattern.

2.44BindingRestElementEcmaify ( rest )

  1. Assert: rest is a Binding.
  2. Let restBinding be ? Ecmaify(rest).
  3. If rest is a BindingPattern, then let restElem0 be BindingPattern : restBinding.
  4. Else let restElem0 be restBinding.
  5. Return BindingRestElement : ... restElem0.

2.45EcmaifyScript ( s )

  1. NOTE: This may be called when a binary AST corresponding to a script is evaluated via BinaryASTScriptEvaluationJob.
  2. Assert: s is a Script.
  3. Let enclosingScope be the current asserted scope.
  4. Set the current asserted scope to s.scope.
  5. Perform AddAssertedScopeTreeNode(s.scope, enclosingScope).
  6. Let dirsStmts be s.directives prepended to s.statements.
  7. Let script be an empty Parse Node.
  8. If s.directives has length 0 and s.statements has length 0, then
    1. Set script to Script :.
  9. Else,
    1. Let dirStmts be s.directives concatenated with s.statements.
    2. Let stmts be ? StatementListEcmaify(dirStmts).
    3. Set script to Script : stmts.
  10. Perform ? CheckAssertedScope(s.scope, script).
  11. Set the current asserted scope to enclosingScope.
  12. Return script.

2.46EcmaifyModule ( m )

  1. NOTE: This may be called when a binary AST corresponding to a module is evaluated via BinaryASTTopLevelModuleEvaluationJob.
  2. Assert: m is a Module.
  3. TODO.

2.47EcmaifyFormalParameters ( params )

  1. NOTE: This may be called when a FormalParameters tagged as being produced by a binary AST FormalParameters is evaluated.
  2. Assert: params is a FormalParameters.
  3. If params.items has length 0, then
    1. If params.rest is null, then return FormalParameters :.
    2. Else,
      1. Let rest be FunctionRestParameter : ? BindingRestElementEcmaify(params.rest).
      2. Return FormalParameters : rest.
  4. Else,
    1. Let list be ? FormalParameterListEcmaify(params.items).
    2. If params.rest is null, then return FormalParameters : list.
    3. Else,
      1. Let rest be FunctionRestParameter : ? BindingRestElementEcmaify(params.rest).
      2. Return FormalParameters : list , rest.

2.48EcmaifyCoverArrowParameterList ( params )

  1. NOTE: This may be called when an ArrowParameters tagged as being produced by a binary AST FormalParameters is evaluated.
  2. Assert: params is a FormalParameters.
  3. Let params0 be UniqueFormalParameters : ? EcmaifyFormalParameters(params).
  4. Return params ArrowFormalParameters : ( params0 ).

2.49EcmaifyPropertySetParameterList ( param )

  1. Assert: param is a Parameter.
  2. Let param0Ecmaify(param).
  3. Return PropertySetParameterList : param0.

2.50EcmaifyFunctionBody ( f )

  1. NOTE: This may be called when an EmptyStatement tagged as being produced by a binary AST FunctionBody is evaluated.
  2. Assert: f is a FunctionDeclaration, a FunctionExpression, a Method, a Getter, a Setter, or a ArrowExpression.
  3. Let stmts be an empty Parse Node.
  4. If f.contents.body is a FunctionBody, then
    1. NOTE: Directives must be non-null, but possibly empty, if the function body is a StatementList.
    2. If f is an ArrowExpression and f.directives is null, then throw a SyntaxError.
    3. Let dirStmts be f.directives concatenated with f.contents.body.
    4. Set stmts to ? StatementListEcmaify(dirStmts).
  5. Else,
    1. Assert: f.contents.body is an Expression.
    2. NOTE: Directives must be null if the function is an arrow and the body is an expression.
    3. If f.directives is not null, then throw a SyntaxError.
    4. Let stmt be ReturnStatement : returnExpressionEcmaify(f.contents.body) ;.
    5. Let stmtItem be StatementListItem : stmt.
    6. Let stmts be StatementList : stmtItem.
  6. Let funcStmts be FunctionStatementList : stmts_.
  7. Return FunctionBody : funcStmts.

2.51EcmaifyBlock ( b )

  1. Assert: b is a Block.
  2. Let enclosingScope be the current asserted scope.
  3. Set the current asserted scope to b.scope.
  4. Perform AddAssertedScopeTreeNode(b.scope, enclosingScope).
  5. Let stmts be ? StatementListEcmaify(b.statements).
  6. Let block be Block : { stmts }.
  7. Perform ? CheckAssertedScope(b.scope, block).
  8. Set the current asserted scope to enclosingScope.
  9. Return block.

2.52EcmaifyDirective ( directive )

  1. Assert: directive is a Directive.
  2. Let v be the value of directive.rawValue escaped for double quotes.
  3. Let l be StringLiteral : " v ".
  4. Return Literal : l.

2.53EcmaifyBreakStatement ( brk )

  1. Assert: brk is a BreakStatement.
  2. If brk.label is null, then return BreakStatement : break ;.
  3. Else return BreakStatement : breakLabelIdentifierEcmaify(brk.label) ;.

2.54EcmaifyContinueStatement ( cont )

  1. Assert: cont is a ContinueStatement.
  2. If cont.label is null, then
    1. Return ContinueStatement : continue ;.
  3. Else return ContinueStatement : continueLabelIdentifierEcmaify(cont.label) ;.

2.55EcmaifyClassDeclaration (cls )

  1. Assert: cls is a ClassDeclaration.
  2. TODO.

2.56EcmaifyDebuggerStatement ( dbg )

  1. Assert: dbg is a DebuggerStatement.
  2. Return DebuggerStatement : debugger ;.

2.57EcmaifyEmptyStatement ( e )

  1. Assert: e is an EmptyStatement.
  2. Return EmptyStatement : ;.

2.58EcmaifyExpressionStatement ( expr )

  1. Assert: expr is an ExpressionStatement.
  2. Return ExpressionStatement : ? ExpressionEcmaify(expr.expression) ;.

2.59EcmaifyFunctionDeclaration ( func )

  1. Assert: func is an EagerFunctionDeclaration or a LazyFunctionDeclaration.
  2. Let enclosingScope be the current asserted scope.
  3. Let funcName be ? Ecmaify(func.name).
  4. Perform MaybeSynthesizeThisScope(func).
  5. Let params be ? LazyFormalParametersEcmaify(func).
  6. If func.isAsync is true, then
    1. Let body be AsyncFunctionBody : ? LazyFunctionBodyEcmaify(func).
    2. Set the current asserted scope to enclosingScope.
    3. Return AsyncFunctionDeclaration : async function funcName ( params ) { body }.
  7. Else if func.isGenerator is true, then
    1. Let body be GeneratorBody : ? LazyFunctionBodyEcmaify(func).
    2. Set the current asserted scope to enclosingScope.
    3. Return GeneratorDeclaration : function * funcName ( params ) { body }.
  8. Else,
    1. Let body be ? LazyFunctionBodyEcmaify(func).
    2. Set the current asserted scope to enclosingScope.
    3. Return FunctionDeclaration : function funcName ( params ) { body }.

2.60EcmaifyIfStatement ( if )

  1. Assert: if is an IfStatement.
  2. Let test be ? Ecmaify(if.test).
  3. Let then be ? Ecmaify(if.consequent).
  4. If if.alternate is null, then
    1. Return IfStatement : if ( test ) then.
  5. Else return IfStatement : if ( test ) then elseStatementEcmaify(if.alternate).

2.61EcmaifyDoWhileStatement ( doWhile )

  1. Assert: doWhile is a DoWhileStatement.
  2. Let test be ? ExpressionEcmaify(doWhile.test).
  3. Let body be ? StatementEcmaify(doWhile.body).
  4. Return IterationStatement : do body while ( test ) ;.

2.62EcmaifyForInStatement ( forIn )

  1. Assert: forIn is a ForInStatement.
  2. Let left be an empty Parse Node.
  3. Let right be ? AssignmentExpressionEcmaify(forIn.right).
  4. Let body be ? StatementEcmaify(forIn.body).
  5. If forIn.left is a ForInOfBinding, then
    1. If forIn.left.kind is "var", then
      1. Let varBinding be ForBinding : ? Ecmaify(forIn.left.binding).
      2. Return IterationStatement : for ( var varBinding in right ) body.
    2. Else set left to ? Ecmaify(forIn.left).
  6. Else set left to ? LeftHandSideExpressionEcmaify(forIn.left).
  7. Return IterationStatement : for ( left in right ) body.

2.63EcmaifyForOfStatement ( forOf )

  1. Assert: forOf is a ForOfStatement.
  2. Let left be an empty Parse Node.
  3. Let right be ? AssignmentExpressionEcmaify(forOf.right).
  4. Let body be ? StatementEcmaify(forOf.body).
  5. If forOf.left is a ForInOfBinding, then
    1. If forOf.left.kind is "var", then
      1. Let varBinding be ForBinding : ? Ecmaify(forOf.left.binding).
      2. Return IterationStatement : for ( var varBinding of right ) body.
    2. Else set left to ? Ecmaify(forOf.left).
  6. Else set left to ? LeftHandSideExpressionEcmaify(forOf.left).
  7. Return IterationStatement : for ( left of right ) body.

2.64EcmaifyForStatement ( for )

  1. Assert: for is a ForStatement.
  2. Let init, test, and update be empty Parse Nodes.
  3. If for.test is not null, then set test to ? ExpressionEcmaify(for.test).
  4. If for.update is not null, then set update to ? ExperssionEcmaify(for.test).
  5. Let body be ? StatementEcmaify(for.body).
  6. If for.init is not null, then
    1. If for.init is a VariableDeclaration, then
      1. If for.init.kind is "var", then
        1. Let varDecls be ? VariableDeclarationListEcmaify(for.init.declarators).
        2. Return IterationStatement : for ( var varDecls ; test ; update ) body.
      2. Else set init to LexicalDeclaration : ? Ecmaify(for.init.kind) ? BindingListEcmaify(for.init.declarators).
    2. Else set init to ? LeftHandSideExpressionEcmaify(for.init).
  7. Return IterationStatement : for ( init ; test ; update ) body.

2.65EcmaifyWhileStatement ( while )

  1. Assert: while is a WhileStatement.
  2. Let test be ? ExpressionEcmaify(while.test).
  3. Let body be ? StatementEcmaify(while.body).
  4. Return IterationStatement : while ( test ) body.

2.66EcmaifyLabelledStatement ( labelled )

  1. Assert labelled is a LabelledStatement.
  2. Let body be an empty Parse Node.
  3. If labelled.body is a FunctionDeclaration, then
    1. If labelled.body.isAsync is true or labelled.body.isGenerator is true, then throw a SyntaxError exception.
    2. Set body to ? Ecmaify(labelled.body).
  4. Else set body to ? StatementEcmaify(labelled.body).
  5. Let item be LabelledItem : body.
  6. Return LabelledStatement : ? LabelIdentifierEcmaify(labelled.label) : item.

2.67EcmaifyReturnStatement ( ret )

  1. Assert: ret is a ReturnStatement.
  2. If ret.expression is null, then
    1. Return ReturnStatement : return ;.
  3. Else return ReturnStatement : returnExpressionEcmaify(ret.expression).

2.68EcmaifySwitchStatement ( switch )

  1. Assert: switch is a SwitchStatement.
  2. Let expr be ? ExpressionEcmaify(switch.discriminant).
  3. Let block be an empty Parse Node.
  4. If switch.cases has length 0, then set block to CaseBlock : { }.
  5. Else,
    1. Let clauses be ? CaseClausesEcmaify(switch.cases).
    2. Set block to CaseBlock : { clauses }.
  6. Return SwitchStatement : switch ( expr ) block.

2.69EcmaifySwitchStatementWithDefault ( switch )

  1. Assert: switch is a SwitchStatementWithDefault.
  2. Let expr be ? ExpressionEcmaify(switch.discriminant).
  3. Let defaultClause be ? DefaultClauseEcmaify(switch.defaultCase).
  4. Let block be an empty Parse Node.
  5. If switch.preDefaultCases has length 0, then
    1. If switch.postDefaultCases has length 0, then
      1. Set block to CaseBlock : { defaultClause }.
    2. Else,
      1. Let postDefaultClauses be ? CaseClausesEcmaify(switch.postDefaultCases).
      2. Set block to CaseBlock : { defaultClause postDefaultClauses }.
  6. Else if switch.postDefaultCases has length 0, then
    1. Let preDefaultClauses be ? CaseClausesEcmaify(switch.preDefaultCases).
    2. Set block to CaseBlock : { preDefaultClauses defaultClause }
  7. Else,
    1. Let preDefaultClauses be ? CaseClausesEcmaify(switch.preDefaultCases).
    2. Let postDefaultClauses be ? CaseClausesEcmaify(switch.postDefaultCases).
    3. Set block to CaseBlock : { preDefaultClauses defaultClause postDefaultClauses }.
  8. Return SwitchStatement : switch ( expr ) block.

2.70EcmaifyThrowStatement ( throw )

  1. Assert: throw is a ThrowStatement.
  2. Return ThrowStatement : throwExpressionEcmaify(throw.expression).

2.71EcmaifyTryCatchStatement ( tryCatch )

  1. Assert: tryCatch is a TryCatchStatement.
  2. Let block be ? Ecmaify(tryCatch.body).
  3. Let catch be ? Ecmaify(tryCatch.catchClause).
  4. Return TryStatement : try block catch.

2.72EcmaifyTryFinallyStatement ( tryFinally )

  1. Assert: tryFinally is a TryFinallyStatement.
  2. Let block be ? Ecmaify(tryFinally.body).
  3. Let finally be Finally : finallyEcmaify(tryFinally.finalizer).
  4. If tryFinally.catch is null, then
    1. Return TryStatement : try block finally.
  5. Else,
    1. Let catch be ? Ecmaify(tryFinally.catchClause).
    2. Return TryStatement : try block catch finally.

2.73EcmaifyVariableDeclaration ( decl )

  1. Assert: decl is a VariableDeclaration.
  2. If decl.kind is "var", then
    1. Let varDecls be ? VariableDeclarationListEcmaify(decl.declarators).
    2. Return VariableStatement : var varDecls ;.
  3. Else,
    1. Let letOrConst be ? Ecmaify(decl.kind).
    2. Let lexDecls be ? BindingListEcmaify(decl.declarators).
    3. Return LexicalDeclaration : letOrConst lexDecls ;.

2.74EcmaifyWithStatement ( with )

  1. Assert: with is a WithStatement.
  2. Let expr be ? ExpressionEcmaify(with._object).
  3. Let body be ? StatementEcmaify(with.body).
  4. Return WithStatement : with ( expr ) body.

2.75EcmaifyLiteralBooleanExpression ( litBool )

  1. Assert: litBool is a LiteralBooleanExpression.
  2. Let l be an empty Parse Node.
  3. If litBool.value is true, then set l to BooleanLiteral : true.
  4. Else set l to BooleanLiteral : false.
  5. Return Literal : l.

2.76EcmaifyLiteralInfinityExpression ( litInfty )

  1. NOTE: The full tree of numeric literals is elided here and left as an exercise to the reader.
  2. NOTE: This node is not for the Infinity identifier, but for literal decimals whose mathematical values exceed the bounds of IEEE doubles.
  3. Assert: litInfty is a LiteralInfinityExpresion.
  4. Let l0 be DecimalLiteral : 2e308.
  5. Let l1 be NumericLiteral : l0.
  6. Return Literal : l1.

2.77EcmaifyLiteralNullExpression ( litNull )

  1. Assert: litNull is a LiteralNullExpression.
  2. Let l be NullLiteral : null.
  3. Return Literal : l.

2.78EcmaifyLiteralNumericExpression ( litNumeric )

  1. NOTE: The full tree of numeric literals is elided here and left as an exercise to the reader.
  2. NOTE: The value in litNumeric is positive, non-NaN, and finite.
  3. Assert: litNumeric is a LiteralNumericExpression.
  4. Let l be DecimalLiteral : litNumeric.value.
  5. Return Literal : l.

2.79EcmaifyLiteralRegExpExpression ( litRegexp )

  1. NOTE: The full tree of regular expression literals is elided here and left as an exercise to the reader.
  2. Assert: litRegExp is a LiteralRegExpExpression.
  3. Let body be RegularExpressionBody : litRegexp.pattern.
  4. Let flags be RegularExpressionFlags : litRegexp.flags.
  5. Return RegularExpressionLiteral : / body / flags.

2.80EcmaifyLiteralStringExpression ( litStr )

  1. Assert: litStr is a LiteralStringExpression.
  2. Let v be the value of litStr.value escaped for double quotes.
  3. Let l be StringLiteral : " v ".
  4. Return Literal : l.

2.81EcmaifyArrayExpression ( litArray )

  1. Assert: litArray is an ArrayExpression or an ArrayAssignmentTarget.
  2. NOTE: While binary AST distinguishes between array literals used as right-hand side expressions and used as left-hand side expressions, the ECMAScript lexical grammar deals with this via a cover grammar and reparsing. While it is preferable to transform ArrayAssignmentTarget directly to ArrayAssignmentPattern, doing so would require changing the ECMAScript spec to consume that production without reparsing.
  3. If litArray.elements has length 0, then
    1. Return ArrayLiteral : [ ].
  4. Let and elementList and elisions be the results of ? ElementListEcmaify(litArray.elements).
  5. If elementList is empty:
    1. Assert: elisions is not empty.
    2. Return ArrayLiteral : [ elisions ].
  6. Else,
    1. If elisions is empty, then return ArrayLiteral : [ elementList ].
    2. Else return ArrayLiteral : [ elementList , elisions ].

2.82EcmaifyArrowExpression ( litArrow )

  1. NOTE: Arrow expressions are canonicalized to use parenthesized parameters and braced bodies.
  2. Assert: litArrow is an EagerArrowExpression or a LazyArrowExpression.
  3. Let enclosingScope be the current asserted scope.
  4. Let params be ? LazyCoverArrowParameterListEcmaify(litArrow).
  5. Let lazyBody be ? LazyFunctionBodyEcmaify(litArrow).
  6. Set the current asserted scope to enclosingScope.
  7. If litArrow.isAsync is true, then
    1. Let asyncHead be AsyncArrowHead : async params.
    2. Let asyncBody0 be AsyncFunctionBody : lazyBody.
    3. Let asyncBody be AsyncConciseBody : { asyncBody0 }.
    4. Return AsyncArrowFunction : asyncHead => asyncBody.
  8. Else,
    1. Let body be ConciseBody : { lazyBody }.
    2. Return ArrowFunction : params => body.

2.83EcmaifyAssignmentExpression ( assign )

  1. Assert: assign is an AssignmentExpression.
  2. Let lhs be ? LeftHandSideExpressionEcmaify(assign.binding).
  3. Let rhs be ? AssignmentExpressionEcmaify(assign.expression).
  4. Return AssignmentExpression : lhs = rhs.

2.84EcmaifyBinaryExpression ( bin )

  1. Assert: bin is a BinaryExpression.
  2. If bin.operator is ",", then
    1. Let left be ? ExpressionEcmaify(bin.left).
    2. Let right be ? AssignmentExpressionEcmaify(bin.right).
    3. Return Expression : left , right.
  3. Else if bin.operator is "||", then
    1. Let left be ? LogicalOREcmaify(bin.left).
    2. Let right be ? LogicalANDEcmaify(bin.right).
    3. Return LogicalORExpression : left || right.
  4. Else if bin.operator is "&&", then
    1. Let left be ? LogicalANDEcmaify(bin.left).
    2. Let right be ? BitwiseOREcmaify(bin.right).
    3. Return LogicalANDExpression : left && right.
  5. Else if bin.operator is "|", then
    1. Let left be ? BitwiseOREcmaify(bin.left).
    2. Let right be ? BitwiseXOREcmaify(bin.right).
    3. Return BitwiseORExpression : left | right.
  6. Else if bin.operator is "^", then
    1. Let left be ? BitwiseXOREcmaify(bin.left).
    2. Let right be ? BitwiseANDEcmaify(bin.right).
    3. Return BitwiseXORExpression : left ^ right.
  7. Else if bin.operator is "&", then
    1. Let left be ? BitwiseANDEcmaify(bin.left).
    2. Let right be ? EqualityExpressionEcmaify(bin.right).
    3. Return BitwiseANDExpression : left & right.
  8. Else if bin.operator is "==", "!=", "===", or "!==", then
    1. Let left be ? EqualityExpressionEcmaify(bin.left).
    2. Let right be ? RelationalExpressionEcmaify(bin.right).
    3. If bin.operator is "==", then return EqualityExpression : left == right.
    4. Else if bin.operator is "!=", then return EqualityExpression : left != right.
    5. Else if bin.operator is "===", then return EqualityExpression : left === right.
    6. Else return EqualityExpression : left !== right.
  9. Else if bin.operator is "<", ">", "<=", ">=", "instanceof", or "in", then
    1. Let left be ? RelationExpressionEcmaify(bin.left).
    2. Let right be ? ShiftExpressionEcmaify(bin.right).
    3. If bin.operator is "<" return RelationalExpression : left < right.
    4. Else if bin.operator is ">", then return RelationalExpression : left > right.
    5. Else if bin.operator is "<=" return RelationalExpression : left <= right.
    6. Else if bin.operator is ">=", then return RelationalExpression : left >= right.
    7. Else if bin.operator is "instanceof", then return RelationalExpression : left instanceof right.
    8. Else return RelationalExpression : left in right.
  10. Else if bin.operator is "<<", ">>", or ">>>", then
    1. Let left be ? ShiftExpressionEcmaify(bin.left).
    2. Let right be ? AdditiveExpressionEcmaify(bin.right).
    3. If bin.operator is "<<", then return ShiftExpression : left << right.
    4. Else if bin.operator is ">>", then return ShiftExpression : left >> right.
    5. Else return ShiftExpression : left >>> right.
  11. Else if bin.operator is "+" or "-", then
    1. Let left be ? AdditiveExpressionEcmaify(bin.left).
    2. Let right be ? MultiplicativeExpressionEcmaify(bin.right).
    3. If bin.operator is "+", then return AdditiveExpression : left + right.
    4. Else return AdditiveExpression : left - right.
  12. Else if bin.operator is "*", "/", or "%", then
    1. Let left be ? MultiplicativeExpressionEcmaify(bin.left).
    2. Let right be ? ExponentationExpressionEcmaify(bin.right).
    3. Let op be an empty Parse Node.
    4. If bin.operator is "*", then set op to MultiplicativeOperator : *
    5. Else if bin.operator is "/", then set op to MultiplicativeOperator : /.
    6. Else if bin.operator is "%", then set op to MultiplicativeOperator : %.
    7. Return MultiplicativeExpression : left op right.
  13. Else,
    1. Let left be ? UpdateExpressionEcmaify(bin.left).
    2. Let right be ? ExponentationExpressionEcmaify(bin.right).
    3. Return ExponentiationExpression : left ** right.

2.85EcmaifyCallExpression ( call )

  1. Assert: call is a CallExpression.
  2. Let args be ? ArgumentsEcmaify(call.arguments).
  3. If call.callee is a Super, then
    1. Let superCall be SuperCall : super args.
    2. Return CallExpression : superCall.
  4. Else,
    1. NOTE: CallExpressions are canonicalized to have the callee to always be parenthesized.
    2. Let callee be ? MemberExpressionEcmaify(call.callee).
    3. Return CallExpression : callee args.

2.86EcmaifyCompoundAssignmentExpression ( assign )

  1. Assert: assign is a CompoundAssignmentExpression.
  2. Let lhs be ? LeftHandSideExpressionEcmaify(assign.binding)
  3. Let rhs be ? AssignmentExpressionEcmaify(assign.expression).
  4. Let op be an empty Parse Node.
  5. If assign.operator is "|=" then set op to AssignmentOperator : |=.
  6. Else if assign.operator is "/=" then set op to AssignmentOperator : /=.
  7. Else if assign.operator is "%=" then set op to AssignmentOperator : %=.
  8. Else if assign.operator is "+=" then set op to AssignmentOperator : +=.
  9. Else if assign.operator is "-=" then set op to AssignmentOperator : -=.
  10. Else if assign.operator is "<<=" then set op to AssignmentOperator : <<=.
  11. Else if assign.operator is ">>=" then set op to AssignmentOperator : >>=.
  12. Else if assign.operator is ">>>=" then set op to AssignmentOperator : >>>=.
  13. Else if assign.operator is "&=" then set op to AssignmentOperator : &=.
  14. Else if assign.operator is "^=" then set op to AssignmentOperator : ^=.
  15. Else if assign.operator is "|=" then set op to AssignmentOperator : |=.
  16. Else set op to AssignmentOperator : **=.
  17. Return AssignmentExpression : lhs op rhs.

2.87EcmaifyComputedMemberExpression ( getelem )

  1. Assert: getelem is a ComputedMemberExpression or a ComputedMemberAssignmentTarget.
  2. Let expr be ? ExpressionEcmaify(getelem.expression).
  3. If getelem._object is a Super, then
    1. Let superProp be SuperProperty : super [ expr ].
    2. Return MemberExpression : superProp.
  4. Else,
    1. Let base be ? MemberExpressionEcmaify(getelem._object).
    2. Return MemberExpression : base [ expr ].

2.88EcmaifyConditionalExpression ( hook )

  1. Assert: hook is a ConditionalExpression.
  2. Let test be ? LogicalORExpressionEcmaify(hook.test).
  3. Let then be ? AssignmentExpressionEcmaify(hook.consequent).
  4. Let else be ? AssignmentExpressionEcmaify(hook.alternate).
  5. Return ConditionalExpression : test ? then : else.

2.89EcmaifyClassExpression ( cls )

  1. Assert: cls is a ClassExpression.
  2. TODO.

2.90EcmaifyFunctionExpression ( func )

  1. Assert: func is an EagerFunctionExpression or a LazyFunctionExpression.
  2. Let enclosingScope be the current asserted scope.
  3. Let maybeFuncName be an empty Parse Node.
  4. If func.name not null, then
    1. Set maybeFuncName to ? Ecmaify(func.name).
    2. Perform MaybeSynthesizeNamedLambdaScope(func).
  5. Perform MaybeSynthesizeThisScope(func).
  6. Let params be ? LazyFormalParametersEcmaify(func).
  7. If func.isAsync is true, then
    1. Let body be AsyncFunctionBody : ? LazyFunctionBodyEcmaify(func).
    2. Set the current asserted scope to enclosingScope.
    3. Return AsyncFunctionExpression : async function maybeFuncName ( params ) { body }.
  8. Else if func.isGenerator is true, then
    1. Let body be GeneratorBody : ? LazyFunctionBodyEcmaify(func).
    2. Set the current asserted scope to enclosingScope.
    3. Return GeneratorExpression : function * maybeFuncName ( params ) { body }.
  9. Else,
    1. Let body be ? LazyFunctionBodyEcmaify(func).
    2. Set the current asserted scope to enclosingScope.
    3. Return FunctionExpression : function maybeFuncName ( params ) { body }.

2.91EcmaifyIdentifierExpression ( ident )

  1. Assert: ident is an IdentifierExpression.
  2. If ident.name is "yield", then return IdentifierReference : yield.
  3. Else if ident.name is "await", then return IdentifierReference : await.
  4. Else return IdentifierReference : ? IdentifierEcmaify(ident.name).

2.92EcmaifyNewExpression ( new )

  1. NOTE: New expressions are canonicalized to the arguments-taking verison.
  2. Assert: new is a NewExpression.
  3. Let callee be ? MemberExpressionEcmaify(new.callee).
  4. Let args be ? ArgumentesEcmaify(new.arguments).
  5. Return MemberExpression: new callee args.

2.93EcmaifyNewTargetExpression ( newTarget )

  1. Assert: newTarget is a NewTargetExpression.
  2. Let n be NewTarget : new . target.
  3. Return MetaProperty : n.

2.94EcmaifyObjectExpression ( litObj )

  1. Assert: litObj is an ObjectExpression or an ObjectAssignmentTarget.
  2. NOTE: While binary AST distinguishes between object literals used as right-hand side expressions and used as left-hand side expressions, the ECMAScript lexical grammar deals with this via a cover grammar and reparsing. While it is preferable to transform ObjectAssignmentTarget directly to ObjectAssignmentPattern, doing so would require changing the ECMAScript spec to consume that production without reparsing.
  3. If litObj.properties has length 0, then return ObjectLiteral : { }.
  4. Else,
    1. Let props be ? PropertyDefinitionListEcmaify(litObj.properties).
    2. Return ObjectLiteral : { props }.

2.95EcmaifyUnaryExpression ( unary )

  1. Assert: unary is an UnaryExpression.
  2. Let operand be ? UnaryExpressionEcmaify(unary.operand).
  3. If unary.operator is "delete", then return UnaryExpression : delete operand.
  4. Else if unary.operator is "void", then return UnaryExpression : void operand.
  5. Else if unary.operator is "typeof", then return UnaryExpression : typeof operand.
  6. Else if unary.operator is "+", then return UnaryExpression : + operand.
  7. Else if unary.operator is "-", then return UnaryExpression : - operand.
  8. Else if unary.operator is "", then return |UnaryExpression| : operand.
  9. Else return UnaryExpression : ! operand.

2.96EcmaifyStaticMemberExpression ( getprop )

  1. Assert: getprop is a StaticMemberExpression or a StaticMemberAssignmentTarget.
  2. If getprop._object is a Super, then
    1. Let superProp be SuperProperty : super . getprop.property.
    2. Return MemberExpression : superProp.
  3. Else,
    1. Let base be ? MemberExpressionEcmaify(getprop._object).
    2. Return MemberExpression : base . getprop.property.

2.97EcmaifyTemplateExpression ( litTemplate )

  1. Assert: litTemplate is a TemplateExpression.
  2. TODO.

2.98EcmaifyThisExpression ( this )

  1. Assert: this is a ThisExpression.
  2. Return PrimaryExpression : this.

2.99EcmaifyUpdateExpression ( upd )

  1. Assert: upd is an UpdateExpression.
  2. If upd.isPrefix is true, then
    1. Let operand be ? UnaryExpressionEcmaify(upd.operand).
    2. If upd.operator is "++", then return UpdateExpression : ++ operand.
    3. Else return UpdateExpression : -- operand.
  3. Else,
    1. Let operand be ? LeftHandSideExpressionEcmaify(upd.operand).
    2. If upd.operator is "++", then return UpdateExpression : operand ++.
    3. Else return UpdateExpression : operand --.

2.100EcmaifyYieldExpression ( yield )

  1. Assert: yield is a YieldExpression.
  2. If yield.expression is null, then
    1. Return YieldExpression : yield.
  3. Else,
    1. Let expr be ? AssignmentExpressionEcmaify(yield.expression).
    2. Return YieldExpression : yield expr.

2.101EcmaifyYieldStarExpression ( yieldStart )

  1. Assert: yieldStar is a YieldStarExpression.
  2. Let expr be ? AssignmentExpressionEcmaify(yieldStar.expression).
  3. Return YieldExpression : yield * expr.

2.102EcmaifyAwaitExpression ( await )

  1. Assert: await is an AwaitExpression.
  2. Let expr be ? UnaryExpressionEcmaify(await.expression).
  3. Return AwaitExpression : await expr.

2.103EcmaifyComputedPropertyName ( name )

  1. Assert: name is a ComputedPropertyName.
  2. Let expr be ? AssignmentExpressionEcmaify(name.expression).
  3. Return ComputedPropertyName : [ expr ].

2.104EcmaifyLiteralPropertyName ( name )

  1. NOTE: Literal property names are canonicalized to double quoted string literals.
  2. Assert: name is a LiteralPropertyName.
  3. If name.value is the empty string, then throw a SyntaxError exception.
  4. Let v be the value of name.value escaped for double quotes.
  5. Let l be StringLiteral : " v ".
  6. Return LiteralPropertyName : l.

2.105EcmaifyMethod ( method )

  1. Assert: method is an EagerMethod or a LazyMethod.
  2. Let enclosingScope be the current asserted scope.
  3. Perform MaybeSynthesizeThisScope(func).
  4. Let name be PropertyName : ? Ecmaify(method.name).
  5. Let params be UniqueFormalParameters : ? LazyFormalParametersEcmaify(method).
  6. If method.isAsync is true, then
    1. Let body be AsyncFunctionBody : ? LazyFunctionBodyEcmaify(method).
    2. Set the current asserted scope to enclosingScope.
    3. Let m be AsyncMethod : async name ( params ) { body }.
    4. Return MethodDefinition : m.
  7. Else if method.isGenerator is true, then
    1. Let body be GeneratorBody : ? LazyFunctionBodyEcmaify(method).
    2. Set the current asserted scope to enclosingScope.
    3. Let m GeneratorMethod : * name ( params ) { body }.
    4. Return MethodDefinition : m.
  8. Else,
    1. Let body be ? LazyFunctionBodyEcmaify(method).
    2. Set the current asserted scope to enclosingScope.
    3. Return MethodDefinition : name ( params ) { body }.

2.106EcmaifyGetter ( getter )

  1. Assert: getter is an EagerGetter or a LazyGetter.
  2. Let enclosingScope be the current asserted scope.
  3. Let name be PropertyName : ? Ecmaify(getter.name).
  4. Perform MaybeSynthesizeThisScope(func).
  5. Let body be ? LazyFunctionBodyEcmaify(getter).
  6. Set the current asserted scope to enclosingScope.
  7. Return MethodDefinition : get name ( ) { body }.

2.107EcmaifySetter ( setter )

  1. Assert: setter is an EagerSetter or a LazySetter.
  2. Let enclosingScope be the current asserted scope.
  3. Let name be PropertyName : ? Ecmaify(setter.name).
  4. Perform MaybeSynthesizeThisScope(func).
  5. Let param be ? LazyPropertySetParameterListEcmaify(setter.param).
  6. Let body be ? LazyFunctionBodyEcmaify(setter).
  7. Set the current asserted scope to enclosingScope.
  8. Return MethodDefinition : set name ( param ) { body }.

2.108EcmaifyDataProperty ( prop )

  1. Assert: prop is a DataProperty.
  2. Let name be PropertyName : ? Ecmaify(prop.name).
  3. Let expr be ? AssignmentExpressionEcmaify(prop.expression).
  4. Return PropertyDefinition : name : expr.

2.109EcmaifyShorthandProperty ( prop )

  1. Assert: prop is a ShorthandProperty.
  2. Let ident be ? Ecmaify(prop.name).
  3. Return PropertyDefinition : ident.

2.110EcmaifyBindingIdentifier ( b )

  1. Assert: b is a BindingIdentifier.
  2. If b.name is "yield", then return BindingIdentifier : yield.
  3. Else if b.name is "await", then return BindingIdentifier : await.
  4. Else return BindingIdentifier : ? IdentifierEcmaify(b.name).

2.111EcmaifyObjectBinding ( obj )

  1. Assert: obj is an ObjectBinding.
  2. If obj.properties has length 0, then return ObjectBindingPattern : { }.
  3. Else return ObjectBindingPattern : {BindingPropertyListEcmaify(obj.properties) }.

2.112EcmaifyBindingPropertyIdentifier ( nameBinding )

  1. Assert: nameBinding is a BindingPropertyIdentifier.
  2. Let binding be ? BindingIdentifierEcmaify(nameBinding.binding).
  3. Let init be an empty Parse Node.
  4. If nameBinding.init is not null, then set init to ? InitializerEcmaify(nameBinding.init).
  5. Let singleNameBinding be SingleNameBinding : binding init.
  6. Return BindingProperty : singleNameBinding.

2.113EcmaifyBindingPropertyProperty ( propBinding )

  1. Assert: propBinding is a BindingPropertyProperty.
  2. Let propName be PropertyName : ? Ecmaify(propBinding.name).
  3. Let binding be ? BindingElementEcmaify(propBinding`.binding).
  4. Return BindingProperty : propName : binding.

2.114EcmaifyArrayBinding ( arr )

  1. Assert: arr is an ArrayBinding.
  2. If arr.elements has length 0, then
    1. If arr.rest is null, then return ArrayBindingPattern : [ ].
    2. Else,
      1. Let restElem be ? BindingRestElementEcmaify(arr.rest).
      2. Return ArrayBindingPattern : [ restElem ].
  3. Let elemList and elisions be the results of ? BindingElementListEcmaify(arr.elements).
  4. If elemList is empty, then
    1. If arr.rest is null, then throw a SyntaxError exception.
    2. Else,
      1. Let restElem be ? BindingRestElementEcmaify(arr.rest).
      2. Return ArrayBindingPattern : [ elisions restElem ].
  5. Else,
    1. If arr.rest is null, then
      1. If elisions is not empty, then throw a SyntaxError exception.
      2. Return ArrayBindingPattern : [ elemList ].
    2. Else,
      1. Let restElem be ? BindingRestElementEcmaify(arr.rest).
      2. Return ArrayBindingPattern : [ elemList elisions restElem ].

2.115EcmaifyBindingWithInitializer ( bindingWithInit )

  1. Assert: bindingWithInit is a BindingWithInitializer.
  2. Let binding be ? Ecmaify(binding.binding).
  3. Let init be ? InitializerEcmaify(binding.init).
  4. If bindingWithInit.binding is a BindingIdentifier, then
    1. Let singleNameBinding be SingleNameBinding : binding init.
    2. Return BindingElement : singleNameBinding.
  5. Else return BindingElement : binding init.

2.116EcmaifyAssignmentTargetWithInitializer ( assignTargetWithInit )

  1. Assert: assignTargetWithInit is an AssignmentTargetWithInitializer.
  2. Let lhs be LeftHandSideExpression(assignTargetWithInit.binding).
  3. Let rhs be AssignmentExpression(assignTargetWithInit.init).
  4. Return AssignmentExpression : lhs = rhs.

2.117EcmaifyAssignmentTargetPropertyIdentifier ( assignPropIdent )

  1. Assert: assignPropIdent is an AssignmentTargetPropertyIdentifier.
  2. Let ident be ? IdentifierReferenceEcmaify(assignPropIdent.binding.name).
  3. Let propDef0 be an empty Parse Node.
  4. If assignPropIdent.init is not null, then
    1. Let init be ? InitializerEcmaify(assignPropIdent.init).
    2. Set propDef0 to CoverInitializedName : ident init.
  5. Else set propDef0 to ident.
  6. Return PropertyDefinition : propDef0.

2.118EcmaifyAssignmentTargetPropertyProperty ( assignPropProp )

  1. Assert: assignPropProp is an AssignmentTargetPropertyProperty.
  2. Let propName be PropertyName : ? Ecmaify(assignPropProp.name).
  3. Let assignExpr be ? AssignmentExpressionEcmaify(assignProp.binding).
  4. Return PropertyDefinition : propName : assignExpr.

2.119EcmaifyForInOfBinding ( b )

  1. Assert: b is a ForInOfBinding.
  2. Assert: b.kind is not "var".
  3. Let binding be ForBinding : ? Ecmaify(b.binding).
  4. Else return ForDeclaration : ? Ecmaify(b.kind) binding.

2.120EcmaifyParameter ( param )

  1. Assert: param is a Parameter.
  2. Return FormalParameter : ? BindingElementEcmaify(param).

2.121EcmaifyCatchClause ( catchClause )

  1. Assert: catchClause is a CatchClause.
  2. Let enclosingScope be the current asserted scope.
  3. Set the current asserted scope to catchClause.bindingScope.
  4. Perform AddAssertedScopeTreeNode(catchClause.bindingScope, enclosingScope).
  5. Let binding be ? Ecmaify(catchClause.binding).
  6. Let body be ? Ecmaify(catchClause.body).
  7. Let catch be Catch : catch ( binding ) body.
  8. Perform ? CheckAssertedScope(catchClause.bindingScope, catch).
  9. Set the current asserted scope to enclosingScope.
  10. Return catch.

2.122EcmaifyVariableDeclarationKind ( k )

  1. Assert: k is "let" or "const".
  2. If k is "let", then return LetOrConst : let.
  3. Else return LetOrConst : const.

2.123Ecmaify ( node )

  1. Assert: node is a Node.
  2. If node is a Block, then return ? EcmaifyBlock(node).
  3. Else if node is a BreakStatement, then return ? EcmaifyBreakStatement(node).
  4. Else if node is a ContinueStatement, then return ? EcmaifyContinueStatement(node).
  5. Else if node is a ClassDeclaration, then return ? EcmaifyClassDeclaration(node).
  6. Else if node is a DebuggerStatement, then return ? EcmaifyDebuggerStatement(node).
  7. Else if node is a EmptyStatement, then return ? EcmaifyEmptyStatement(node).
  8. Else if node is a ExpressionStatement, then return ? EcmaifyExpressionStatement(node).
  9. Else if node is a FunctionDeclaration, then return ? EcmaifyFunctionDeclaration(node).
  10. Else if node is a IfStatement, then return ? EcmaifyIfStatement(node).
  11. Else if node is a DoWhileStatement, then return ? EcmaifyDoWhileStatement(node).
  12. Else if node is a ForInStatement, then return ? EcmaifyForInStatement(node).
  13. Else if node is a ForOfStatement, then return ? EcmaifyForOfStatement(node).
  14. Else if node is a ForStatement, then return ? EcmaifyForStatement(node).
  15. Else if node is a WhileStatement, then return ? EcmaifyWhileStatement(node).
  16. Else if node is a LabelledStatement, then return ? EcmaifyLabelledStatement(node).
  17. Else if node is a ReturnStatement, then return ? EcmaifyReturnStatement(node).
  18. Else if node is a SwitchStatement, then return ? EcmaifySwitchStatement(node).
  19. Else if node is a SwitchStatementWithDefault, then return ? EcmaifySwitchStatementWithDefault(node).
  20. Else if node is a ThrowStatement, then return ? EcmaifyThrowStatement(node).
  21. Else if node is a TryCatchStatement, then return ? EcmaifyTryCatchStatement(node).
  22. Else if node is a TryFinallyStatement, then return ? EcmaifyTryFinallyStatement(node).
  23. Else if node is a VariableDeclaration, then return ? EcmaifyVariableDeclaration(node).
  24. Else if node is a WithStatement, then return ? EcmaifyWithStatement(node).
  25. Else if node is a LiteralBooleanExpression, then return ? EcmaifyLiteralBooleanExpression(node).
  26. Else if node is a LiteralInfinityExpression, then return ? EcmaifyLiteralInfinityExpression(node).
  27. Else if node is a LiteralNullExpression, then return ? EcmaifyLiteralNullExpression(node).
  28. Else if node is a LiteralNumericExpression, then return ? EcmaifyLiteralNumericExpression(node).
  29. Else if node is a LiteralStringExpression, then return ? EcmaifyLiteralStringExpression(node).
  30. Else if node is a LiteralRegExpExpression, then return ? EcmaifyLiteralRegExpExpression(node).
  31. Else if node is a ArrayExpression, then return ? EcmaifyArrayExpression(node).
  32. Else if node is a ArrowExpression, then return ? EcmaifyArrowExpression(node).
  33. Else if node is a AssignmentExpression, then return ? EcmaifyAssignmentExpression(node).
  34. Else if node is a BinaryExpression, then return ? EcmaifyBinaryExpression(node).
  35. Else if node is a CallExpression, then return ? EcmaifyCallExpression(node).
  36. Else if node is a CompoundAssignmentExpression, then return ? EcmaifyCompoundAssignmentExpression(node).
  37. Else if node is a ComputedMemberExpression, then return ? EcmaifyComputedMemberExpression(node).
  38. Else if node is a ConditionalExpression, then return ? EcmaifyConditionalExpression(node).
  39. Else if node is a ClassExpression, then return ? EcmaifyClassExpression(node).
  40. Else if node is a FunctionExpression, then return ? EcmaifyFunctionExpression(node).
  41. Else if node is a IdentifierExpression, then return ? EcmaifyIdentifierExpression(node).
  42. Else if node is a NewExpression, then return ? EcmaifyNewExpression(node).
  43. Else if node is a NewTargetExpression, then return ? EcmaifyNewTargetExpression(node).
  44. Else if node is a ObjectExpression, then return ? EcmaifyObjectExpression(node).
  45. Else if node is a UnaryExpression, then return ? EcmaifyUnaryExpression(node).
  46. Else if node is a StaticMemberExpression, then return ? EcmaifyStaticMemberExpression(node).
  47. Else if node is a TemplateExpression, then return ? EcmaifyTemplateExpression(node).
  48. Else if node is a ThisExpression, then return ? EcmaifyThisExpression(node).
  49. Else if node is a UpdateExpression, then return ? EcmaifyUpdateExpression(node).
  50. Else if node is a YieldExpression, then return ? EcmaifyYieldExpression(node).
  51. Else if node is a YieldStarExpression, then return ? EcmaifyYieldStarExpression(node).
  52. Else if node is a AwaitExpression, then return ? EcmaifyAwaitExpression(node).
  53. Else if node is a ComputedPropertyName, then return ? EcmaifyComputedPropertyName(node).
  54. Else if node is a LiteralPropertyName, then return ? EcmaifyLiteralPropertyName(node).
  55. Else if node is a LiteralPropertyName, then return ? EcmaifyLiteralPropertyName(node).
  56. Else if node is a Method, then return ? EcmaifyMethod(node).
  57. Else if node is a Getter, then return ? EcmaifyGetter(node).
  58. Else if node is a Setter, then return ? EcmaifySetter(node).
  59. Else if node is a DataProperty, then return ? EcmaifyDataProperty(node).
  60. Else if node is a ShorthandProperty, then return ? EcmaifyShorthandProperty(node).
  61. Else if node is a ExportAllFrom, then return ? EcmaifyExportAllFrom(node).
  62. Else if node is a ExportFrom, then return ? EcmaifyExportFrom(node).
  63. Else if node is a ExportLocals, then return ? EcmaifyExportLocals(node).
  64. Else if node is a ExportDefault, then return ? EcmaifyExportDefault(node).
  65. Else if node is a ExportFromSpecifier, then return ? EcmaifyExportFromSpecifier(node).
  66. Else if node is a ExportLocalSpecifier, then return ? EcmaifyExportLocalSpecifier(node).
  67. Else if node is a Export, then return ? EcmaifyExport(node).
  68. Else if node is a ImportSpecifier, then return ? EcmaifyImportSpecifier(node).
  69. Else if node is a ImportNamespace, then return ? EcmaifyImportNamespace(node).
  70. Else if node is a Import, then return ? EcmaifyImport(node).
  71. Else if node is a BindingIdentifier, then return ? EcmaifyBindingIdentifier(node).
  72. Else if node is a ObjectBinding, then return ? EcmaifyObjectBinding(node).
  73. Else if node is a BindingPropertyIdentifier, then return ? EcmaifyBindingPropertyIdentifier(node).
  74. Else if node is a BindingPropertyProperty, then return ? EcmaifyBindingPropertyProperty(node).
  75. Else if node is a ArrayBinding, then return ? EcmaifyArrayBinding(node).
  76. Else if node is a BindingWithInitializer, then return ? EcmaifyBindingWithInitializer(node).
  77. NOTE: Some AssignmentTarget nodes are transformed as expressions instead of the cover grammar variant as the ECMAScript spec does reparsing.
  78. Else if node is a AssignmentTargetIdentifier, then return ? EcmaifyAssignmentTargetIdentifierExpression(node).
  79. Else if node is a AssignmentTargetWithInitializer, then return ? EcmaifyAssignmentTargetWithInitializer(node).
  80. Else if node is a ComputedMemberAssignmentTarget, then return ? EcmaifyComputedMemberExpression(node).
  81. Else if node is a StaticMemberAssignmentTarget, then return ? EcmaifyStaticMemberExpression(node).
  82. Else if node is a ObjectAssignmentTarget, then return ? EcmaifyObjectExpression(node).
  83. Else if node is a AssignmentTargetPropertyIdentifier, then return ? EcmaifyAssignmentTargetPropertyIdentifier(node).
  84. Else if node is a AssignmentTargetPropertyProperty, then return ? EcmaifyAssignmentTargetPropertyProperty(node).
  85. Else if node is a ArrayAssignmentTarget, then return ? EcmaifyArrayExpression(node).
  86. Else if node is a ClassElement, then return ? EcmaifyClassElement(node).
  87. Else if node is a ForInOfBinding, then return ? EcmaifyForInOfBinding(node).
  88. Else return ? EcmaifyDirective(node).

3Evaluation

Binary AST is evaluated via the modified ScriptEvaluationJob and TopLevelModuleEvaluationJob, defined below. The binary AST is transformed into an ECMAScript parse tree. The resulting parse tree is then evaluated using the same evaluation semantics as for parse trees resulting from source text, with the following exceptions.

  1. Transformation of binary ASTs to parse trees may throw exceptions in the same phase as early errors.
  2. Evaluation of a binary AST is inherently lazy at the function boundaries. A function's FunctionBody is not transformed until it is invoked. This means Static Semantics which would have been observable (i.e. by throwing exceptions) at parse time of functions evaluated via source text is deferred until invocation if the function is evaluated via binary AST.

3.1Assertions

Evaluation of binary AST is possibly lazy at function boundaries. Together with AssertedScope, the intent is to allow implementations to start to start code generation without parsing the entire tree. AssertedScope represent assertions that must be checked. A failing assertion throws a SyntaxError exception.

Asserted declared names must match exactly the set of actual declared names exactly in the scope. The asserted captured names in the scope must be a superset of observed captured names. If the presence of direct eval is asserted to be false, then a direct eval must not be observed in the scope. If the presence of direct eval is asserted to be true, a direct eval is allowed to not be observed (i.e. it is conservative).

Note
While asserte scopes are optional, an implementation is prohibited from binding optimizations if they are absent.

The GlobalAssertedScopeTree is a List that is globally available. It is shared by all realms. Prior to the evaluation of any ECMAScript code it is initialized as a new empty List. Elements of the GlobalAssertedScopeTree are Records with the structure defined in Table 1.

Table 1: AssertedScopeTreeNode Record Fields
Field Name Value Meaning
[[AssertedScope]] An AssertedBlockScope, AssertedScriptGlobalScope, AssertedVarScope, AssertedParameterScope, or AssertedBoundNamesScope The payload.
[[Enclosing]] An AssertedScopeTreeNode Record or null The directly enclosing scope.

3.1.1FindAssertedScopeTreeNode ( scope )

  1. Assert: scope is not null.
  2. For each node in GlobalAssertedScopeTree, do
    1. If node.[[AssertedScope]] has the same identity as scope, then return node.
  3. Return null.

3.1.2AddAssertedScopeTreeNode ( scope, enclosing )

  1. Let found be FindAssertedScopeTreeNode(scope).
  2. If found is not null, then
    1. If enclosing is null, then
      1. Assert: found.[[Enclosing]] is null.
    2. Else,
      1. Let enclosingNode be FindAssertedScopeTreeNode(enclosing).
      2. Assert: found.[[Enclosing]] has the same identity as enclosingNode.
  3. Else,
    1. Let node be a new AssertedScopeTreeNode Record {[[AssertedScope]]: scope, [[Enclosing]]: enclosingNode}.
    2. Add node as the last element of GlobalAssertedScopeTree.

3.1.3CheckDeclaredNames ( expectedDeclared, kind, actualDeclared )

  1. Let unseen be a new empty List.
  2. For each d in expectedDeclared, do
    1. If d.kind is kind, then add d.name as the last element of unseen.
  3. For each dn in actualDeclared, do
    1. If dn is not in unseen, then throw a SyntaxError exception.
    2. Remove dn from unseen.
  4. If unseen has length greater than 0, then throw a SyntaxError exception.

3.1.4CheckParameterNames ( expectedParams0, actualParams )

  1. Let expectedParams be a new empty List.
  2. For each p in expectedParams0, do
    1. Add p.name as the last element of expectedParams.
  3. Let idx be 0.
  4. If expectedParams and actualParams have different lengths, then throw a SyntaxError exception.
  5. For each pn in actualParams in List order, do
    1. If expectedParams[idx] is not pn, then throw a SyntaxError exception.
    2. Set idx to idx + 1.
  6. NOTE: This method doesn't check duplicate parameter names. Duplicate parameter names should be caught by Early Errors for FormalParameters.

3.1.5CheckPositionalParameterIndices ( expectedParams, positionalParamNames )

  1. Let paramIndices be CreatePositionalParameterIndices(positionalParamNames).
  2. For each p in expectedParams, do
    1. If p is an AssertedPositionalParameterName, then
      1. If paramIndices contains an item item where item.[[Name]] is p.name and item.[[Index]] is p.index, then
        1. Remove item from paramIndices.
      2. Else,
        1. Throw a SyntaxError exception.
  3. If paramIndices is not empty, throw SyntaxError exception.
  4. NOTE: This method doesn't check duplicate parameter names. Duplicate parameter names should be caught by Early Errors for FormalParameters.

3.1.6CreatePositionalParameterIndices (positionalParamNames )

  1. Let paramIndices be a new empty List.
  2. Let idx be 0.
  3. For each p in positionalParamNames in List order, do
    1. If p is not an empty string, then
      1. Append Record {[[Name]]: p, [[Index]]: idx} to paramIndices.
    2. Set idx to idx + 1.
  4. Return paramIndices.

3.1.7CheckRestParameterName ( expectedParams, restParameterName )

  1. Let paramIndices be CreatePositionalParameterIndices(positionalParamNames).
  2. Let found be false.
  3. For each p in expectedParams, do
    1. If p is an AssertedRestParameterName, then
      1. If restParameterName is p.name, then
        1. If found is true, then
          1. throw a SyntaxError exception.
        2. Let found be true.
      2. Else,
        1. Throw a SyntaxError exception.
  4. if restParameterName is an empty string, then
    1. If found is true, then
      1. Throw a SyntaxError exception.
  5. Else,
    1. If found is false, then
      1. Throw a SyntaxError exception.

3.1.8CheckBoundNames ( expectedBound, actualBound )

  1. Let unseen be a new empty List.
  2. For each b in expectedBound, do
    1. Add b.name as the last element of unseen.
  3. For each dn in actualBound, do
    1. If dn is not in unseen, then throw a SyntaxError exception.
    2. Remove dn from unseen.
  4. If unseen has length greater than 0, then throw a SyntaxError exception.

3.1.9CheckAssertedScope ( scope , parseTree )

  1. Assert: scope is an AssertedBlockScope or an AssertedScriptGlobalScope or an AssertedVarScope or an AssertedParameterScope or an AssertedBoundNamesScope.
  2. Assert: parseTree is a non-empty Parse Node.
  3. NOTE: All asserted declared names must be declared, and all asserted bound names must be bound.
  4. If scope is an AssertedBlockScope or an AssertedScriptGlobalScope or an AssertedVarScope, then
    1. Let varDeclaredNames be the VarDeclaredNames of parseTree.
    2. Perform ? CheckDeclaredNames(scope.declaredNames, "var", varDeclaredNames).
    3. Let lexDeclarations be the LexicallyScopedDeclarations of parseTree.
    4. Let constLexicallyDeclaredNames be a new empty List.
    5. Let nonConstLexicallyDeclaredNames be a new empty List.
    6. For each d in lexDeclarations, do
      1. If IsConstantDeclaration of d is true, then
        1. Append to constLexicallyDeclaredNames the elements of BoundNames of d.
      2. Else,
        1. Append to nonConstLexicallyDeclaredNames the elements of BoundNames of d.
    7. Perform ? CheckDeclaredNames(scope.declaredNames, "const lexical", constLexicallyDeclaredNames).
    8. Perform ? CheckDeclaredNames(scope.declaredNames, "non-const lexical", nonConstLexicallyDeclaredNames).
  5. Else if scope is an AssertedParameterScope, then
    1. NOTE: The positions as well as the names of parameters must match.
    2. Let paramNames be the BoundNames of parseTree.
    3. Perform ? CheckParameterNames(scope.paramNames, paramNames).
    4. Let positionalParamNames be the PositionalParameterNames of parseTree.
    5. Perform ? CheckPositionalParameterIndices(scope.paramNames, positionalParamNames).
    6. Let restParameterName be the RestParameterName of parseTree.
    7. Perform ? CheckRestParameterName(scope.paramNames, restParameterName).
    8. If scope.isSimpleParameterList is not the same value as IsSimpleParameterList of parseTree, then throw a SyntaxError exception.
  6. Else,
    1. Let boundNames be the BoundNames of parseTree.
    2. Perform ? CheckBoundNames(scope.boundNames, boundNames).
  7. NOTE: All free names must have been asserted both declared and captured in an enclosing scope. Non-captured declared names cannot shadow a captured declared name, as in source text. It is permitted to assert a declared name as captured even if it is never observed to be captured.
  8. Let freeNames be the FreeNames of parseTree.
  9. For each fn in freeNames, do
    1. Let scopeNode be FindAssertedScopeTreeNode(scope).
    2. Let outermostScope be null.
    3. Let foundAssertedCapture be false.
    4. Repeat, while scopeNode.[[Enclosing]] is not null and foundAssertedCapture is false,
      1. Let enclosingScope be scopeNode.[[Enclosing]].[[AssertedScope]].
      2. If scope is an AssertedBlockScope or an AssertedScriptGlobalScope or an AssertedVarScope, then
        1. Let enclosingDeclaredOrBoundNames be enclosingScope.declaredNames.
      3. Else if scope is an AssertedParameterScope, then,
        1. Let enclosingDeclaredOrBoundNames be enclosingScope.paramNames.
      4. Else,
        1. Let enclosingDeclaredOrBoundNames be enclosingScope.boundNames.
      5. For each d in enclosingDeclaredOrBoundNames, do
        1. If fn is d.name, then
          1. If d.isCaptured is true, then set foundAssertedCapture to true.
          2. Else throw a SyntaxError exception.
      6. If foundAssertedCapture is false, then,
        1. Set outermostScope to scopeNode.
        2. Set scopeNode to scopeNode.[[Enclosing]].
    5. If foundAssertedCapture is false, then
      1. NOTE: For scripts, global vars are properties on the global object and not bindings.
      2. If outermostScope is not an AssertedScriptGlobalScope, then throw a SyntaxError exception.
  10. NOTE: The presence of a direct eval must have been asserted in an enclosing scope. It is permitted to assert having a direct eval even if a direct eval is never observed in scope.
  11. If parseTree contains a direct eval, then
    1. Let scopeNode be FindAssertedScopeTreeNode(scope).
    2. Let foundAssertedDirectEval to be false.
    3. Repeat, while scopeNode is not null,
      1. If scopeNode.[[AssertedScope]].hasDirectEval is true, then set foundAssertedDirectEval to true.
      2. Else if foundAssertedDirectEval is false, then throw a SyntaxError exception.
      3. Set scopeNode to scopeNode.[[Enclosing]].
    4. If foundAssertedDirectEval is false, then throw a SyntaxError exception.

3.1.10CheckThisCapture ( scope , parseTree )

  1. Assert: scope is an AssertedVarScope or an AssertedParameterScope.
  2. Assert: parseTree is a non-empty Parse Node.
  3. If the value of HasFreeThis of parseTree is false, then return.
  4. Let scopeNode be FindAssertedScopeTreeNode(scope).
  5. Let foundCapturedThis to be false.
  6. Repeat, while scopeNode.[[Enclosing]] is not null and foundCapturedThis is false,
    1. Let enclosingScope be scopeNode.[[Enclosing]].[[AssertedScope]].
    2. If enclosingScope is an AssertedBlockScope, then
      1. If enclosingScope.declaredNames has a single item d and d.name is "this", then
        1. If d.isCaptured is true, then set foundCapturedThis to true.
        2. Else throw a SyntaxError exception.
    3. Else,
      1. Set outermostScope to scopeNode.
      2. Set scopeNode to scopeNode.[[Enclosing]].

3.1.11SynthesizeThisScope ( funcNode , enclosingScope )

  1. NOTE: All functions except arrows may have their this binding captured by a nested arrow. Synthesize a scope that encloses the parameter and body scopes of the function body that contains the sole binding this. It is checked by CheckThisCapture.
  2. Assert: funcNode is not an EagerArrowExpression nor a LazyArrowExpression.
  3. Let synthThisScope be a new AssertedBlockScope.
  4. Let thisDecl be a new AssertedDeclaredName.
  5. Set thisDecl.name to "this".
  6. Set thisDecl.kind to "non-const lexical".
  7. If funcNode.contents.isThisCaptured is true, then
    1. Set thisDecl.isCaptured to true.
  8. Set synthThisScope.declaredNames to be a new FrozenArray<AssertedDeclaredName> of length 1 containing thisDecl.
  9. Set synthThisScope.hasDirectEval to enclosingScope.hasDirectEval.
  10. Perform AddAssertedScopeTreeNode(synthThisScope, enclosingScope).

3.1.12SynthesizeNamedLambdaScope ( funcExprNode , enclosingScope )

  1. NOTE: Named function expressions may capture their name, which synthesizes a block scope containing only the function name enclosing the entire function expression.
  2. Let synthNamedLambdaScope be a new AssertedBlockScope.
  3. Let namedLambdaDecl be a new AssertedDeclaredName.
  4. Set namedLambdaDecl.name to funcExprNode.name.
  5. NOTE: The named lambda name is not exactly a const, but it does not matter for the semantics of asserted scopes.
  6. Set namedLambdaDecl.kind to "const lexical".
  7. Set namedLambdaDecl.isCaptured to true.
  8. Set synthNamedLambdaScope.declaredNames to be a new FrozenArray<AssertedDeclaredName> of length 1 containing namedLambdaDecl.
  9. Set synthNamedLambdaScope.hasDirectEval to enclosingScope.hasDirectEval.
  10. Perform AddAssertedScopeTreeNode(synthNamedLambdaScope, enclosingScope).
  11. Return synthNamedLambdaScope.

3.1.13CheckFunctionLength ( params , maybeLazyNode )

  1. Assert: maybeLazyNode is a FunctionDeclaration, a FunctionExpression, a Method, a Getter, a Setter, or an ArrowExpression.
  2. Assert: params is not tagged as being produced by an AST node.
  3. If maybeLazyNode is a Getter, then
    1. Let length be 0.
  4. Else,
    1. Let length be maybeLazyNode.length.
  5. If length is not equal to ExpectedArgumentCount of params, then
    1. Throw a SyntaxError

3.1.14Static Semantics

FreeNames is a new Static Semantics that collects uses of unbound variables.

3.1.14.1Static Semantics: FreeNames

Unless overridden, Parse Nodes have the following default definition.

  1. Let freeNames be a new empty List.
  2. For each IdentifierReference contained in this Parse Node, do
    1. Let usedName be the FreeNames of IdentifierReference.
    2. If usedName is not in freeNames, add usedName as the last element of freeNames.
  3. Return freeNames.

3.1.14.2Static Semantics: FreeNames

IdentifierReference:yield
  1. Return « "yield" ».
IdentifierReference:await
  1. Return « "await" ».
IdentifierReference:Identifier
  1. Return « StringValue of Identifier ».

3.1.14.3Static Semantics: FreeNames

Block:{StatementList}
  1. Let freeNames be the FreeNames of StatementList.
  2. Let lexicallyDeclaredNames be the LexicallyDeclaredNames of StatementList.
  3. For each dn in lexicallyDeclaredNames, do
    1. Remove dn from freeNames.
  4. Return freeNames.
StatementList:StatementListStatementListItem
  1. Let freeNames be FreeNames of StatementList.
  2. Append to freeNames the elements of the FreeNames of StatementListItem.
  3. Remove duplicate entries from freeNames.
  4. Return freeNames.

3.1.14.4Static Semantics: FreeNames

FunctionBody:FunctionStatementList
  1. Let freeNames be the FreeNames of FunctionStatementList.
  2. Let varDeclaredNames be the VarDeclaredNames of FunctionStatementList.
  3. For each vn in varDeclaredNames, do
    1. Remove vn from freeNames.
  4. Let lexicallyDeclaredNames be the LexicallyDeclaredNames of FunctionStatementList.
  5. For each dn in lexicallyDeclaredNames, do
    1. Remove dn from freeNames.
  6. Return freeNames.

3.1.14.5Static Semantics: FreeNames

ScriptBody:StatementList
  1. Let freeNames be the FreeNames of StatementList.
  2. Let varDeclaredNames be the VarDeclaredNames of StatementList.
  3. For each vn in varDeclaredNames, do
    1. Remove vn from freeNames.
  4. Let lexicallyDeclaredNames be the LexicallyDeclaredNames of StatementList.
  5. For each dn in lexicallyDeclaredNames, do
    1. Remove dn from freeNames.
  6. Return freeNames.

HasFreeThis is a new Static Semantics that returns true if this is free in the Parse Node (i.e. either used directly or in a nested arrow expression).

3.1.14.6Static Semantics: HasFreeThis

Unless overridden, Parse Nodes have the following default definition.

  1. For each Parse Node child contained in this Parse Node, do
    1. If HasFreeThis of child is true, then return true.
  2. Return false.

3.1.14.7Static Semantics: HasFreeThis

PrimaryExpression:this
  1. Return true.

3.1.14.8Static Semantics: HasFreeThis

HoistableDeclaration:[empty]
  1. Return false.

3.1.14.9Static Semantics: HasFreeThis

FunctionExpression:[empty]
  1. Return false.

3.1.14.10Static Semantics: HasFreeThis

AsyncFunctionExpression:[empty]
  1. Return false.

3.1.14.11Static Semantics: HasFreeThis

AsyncGeneratorExpression:[empty]
  1. Return false.

3.1.14.12Static Semantics: HasFreeThis

MethodDefinition:[empty]
  1. Return false.

3.1.14.13Static Semantics: PositionalParameterNames

Collect the positional formal parameter names.

With parameters formalParameters.

FormalParameters:[empty]
  1. Return a new empty List.
FormalParameters:FunctionRestParameter
  1. Return a new empty List.
FormalParameters:FormalParameterList
  1. Return the PositionalParameterNames of FormalParameterList.
FormalParameters:FormalParameterList
  1. Return the PositionalParameterNames of FormalParameterList.
FormalParameters:FormalParameterList
  1. Return the PositionalParameterNames of FormalParameterList.
FormalParameterList:FormalParameter
  1. Return the PositionalParameterNames of FormalParameter.
FormalParameterList:FormalParameterList
  1. Let params be PositionalParameterNames of FormalParameterList.
  2. Append to params the PositionalParameterNames of FormalParameter.
  3. Return params
FormalParameter:BindingIdentifierInitializer_opt
  1. Return the PositionalParameterNames of BindingIdentifier.
FormalParameter:Identifier
  1. Return a new List containing the StringValue of Identifier.
FormalParameter:yield
  1. Return a new List containing "yield".
FormalParameter:await
  1. Return a new List containing "await".
FormalParameter:BindingPatternInitializer_opt
  1. Return a new List containing an empty string.

3.1.14.14Static Semantics: RestParameterName

Return the rest parameter name.

With parameters formalParameters.

FormalParameters:[empty]
  1. Return an empty string.
FormalParameters:FunctionRestParameter
  1. Return the RestParameterName of FunctionRestParameter.
FormalParameters:FormalParameterList
  1. Return an empty string.
FormalParameters:FormalParameterList
  1. Return an empty string.
FormalParameters:FormalParameterList
  1. Return the RestParameterName of FunctionRestParameter.
FormalParameter:BindingIdentifierInitializer_opt
  1. Return the RestParameterName of BindingIdentifier.
FormalParameter:Identifier
  1. Return the StringValue of Identifier.
FormalParameter:yield
  1. Return "yield".
FormalParameter:await
  1. Return "await".
FormalParameter:BindingPatternInitializer_opt
  1. Return an empty string.

3.1.14.15Static Semantics: ExpectedArgumentCount

When FormalParameters is tagged as being produced by lazyNode.

FormalParameters:FormalParameters
  1. Return lazyNode.length.

3.1.15RunJobs ( )

The abstract operation RunJobs is modified as follows.

  1. Perform ? InitializeHostDefinedRealm().
  2. In an implementation-dependent manner, obtain the ECMAScript source texts (see clause 10), ECMAScript ASTs (see Tree Grammar), and any associated host-defined values for zero or more ECMAScript scripts, ECMAScript modules, ECMAScript Script ASTs, and/or ECMAScript Module ASTs. For each such sourceTextsourceTextOrAST and hostDefined, do
    1. If sourceText is the source code of a script or a Script, then
      1. Perform EnqueueJob("ScriptJobs", ScriptEvaluationJob, « sourceTextsourceTextOrAST, hostDefined »).
    2. Else sourceText is the source code of a module or a Module,
      1. Perform EnqueueJob("ScriptJobs", TopLevelModuleEvaluationJob, « sourceTextsourceTextOrAST, hostDefined »).
  3. Repeat,
    1. Suspend the running execution context and remove it from the execution context stack.
    2. Assert: The execution context stack is now empty.
    3. Let nextQueue be a non-empty Job Queue chosen in an implementation-defined manner. If all Job Queues are empty, the result is implementation-defined.
    4. Let nextPending be the PendingJob record at the front of nextQueue. Remove that record from nextQueue.
    5. Let newContext be a new execution context.
    6. Set newContext's Function to null.
    7. Set newContext's Realm to nextPending.[[Realm]].
    8. Set newContext's ScriptOrModule to nextPending.[[ScriptOrModule]].
    9. Push newContext onto the execution context stack; newContext is now the running execution context.
    10. Perform any implementation or host environment defined job initialization using nextPending.
    11. Let result be the result of performing the abstract operation named by nextPending.[[Job]] using the elements of nextPending.[[Arguments]] as its arguments.
    12. If result is an abrupt completion, perform HostReportErrorsresult.[[Value]] »).

3.1.16ScriptEvaluationJob ( sourceTextOrAST, hostDefined )

The abstract operation ScriptEvaluationJob is modified as follows.

  1. Assert: sourceTextsourceTextOrAST is an ECMAScript source text (see clause 10) or a Script (see Tree Grammar).
  2. Let realm be the current Realm Record.
  3. LIf sourceTextOrAST is an ECMAScript source text, then let s be ParseScript(sourceTextsourceTextOrAST, realm, hostDefined).
  4. Else let s be ? TransformASTScript(sourceTextOrAST, realm, hostDefined).
  5. If s is a List of errors or s, then
    1. Perform HostReportErrors(s).
    2. Return NormalCompletion(undefined).
  6. Return ? ScriptEvaluation(s).

3.1.17TransformASTScript ( ast, realm, hostDefined )

TransformASTScript is a new abstract operation.

  1. Assert: The current asserted scope to null.
  2. Let body be ? EcmaifyScript(ast).
  3. Return Script Record {[[Realm]]: realm, [[Environment]]: undefined, [[ECMAScriptCode]]: body, [[HostDefined]]: hostDefined}.

3.1.18ValidateAndUpdateFunctionObject ( funcNode , functionObject, body0, params )

  1. Let prod be an empty Parse Node.
  2. Let body be an empty Parse Node.
  3. If funcNode is a FunctionDeclaration, then
    1. Let funcName be ? Ecmaify(funcNode.name).
    2. If funcNode.isAsync is true, then
      1. Set body toe AsyncFunctionBody : body0.
      2. Set prod AsyncFunctionDeclaration : async function funcName ( params ) { body }.
    3. Else if funcNode.isGenerator is true, then
      1. Set body to GeneratorBody : body0.
      2. Set prod to GeneratorDeclaration : function * funcName ( params ) { body }.
    4. Else,
      1. Set body to body0.
      2. Set prod to FunctionDeclaration : function funcName ( params ) { body }.
  4. Else if funcNode is an ArrowExpression, then
    1. If funcNode.isAsync is true, then
      1. Let asyncHead be AsyncArrowHead : async params.
      2. Let body1 be AsyncFunctionBody : body0.
      3. Set body to AsyncConciseBody : { body1 }.
      4. Set prod to AsyncArrowFunction : asyncHead => body.
    2. Else,
      1. Set body to ConciseBody : { body0 }.
      2. Set prod to ArrowFunction : params => body.
  5. Else if funcNode is a FunctionExpression, then
    1. Let maybeFuncName be an empty Parse Node.
    2. If funcNode.name not null, then set maybeFuncName to ? Ecmaify(funcNode.name).
    3. If funcNode.isAsync is true, then
      1. Set body to AsyncFunctionBody : body0.
      2. Set prod to AsyncFunctionExpression : async function maybeFuncName ( params ) { body }.
    4. Else if funcNode.isGenerator is true, then
      1. Set body to GeneratorBody : body0.
      2. Set prod to GeneratorExpression : function * maybeFuncName ( params ) { body }.
    5. Else,
      1. Set body to body0.
      2. Set prod to FunctionExpression : function maybeFuncName ( params ) { body }.
  6. Else if funcNode is a Method, then
    1. Let name be PropertyName : ? Ecmaify(funcNode.name).
    2. If funcNode.isAsync is true, then
      1. Set body to AsyncFunctionBody : body0.
      2. Let m be AsyncMethod : async name ( params ) { body }.
      3. Set prod to MethodDefinition : m.
    3. Else if funcNode.isGenerator is true, then
      1. Set body to GeneratorBody : body0.
      2. Let m GeneratorMethod : * name ( params ) { body }.
      3. Set prod to MethodDefinition : m.
    4. Else,
      1. Set body to body0.
      2. Set prod to MethodDefinition : name ( params ) { body }.
  7. Else if funcNode is a Getter, then
    1. Let name be PropertyName : ? Ecmaify(funcNode.name).
    2. Set body to body0.
    3. Set prod to MethodDefinition : get name ( ) { body }.
  8. Else,
    1. Assert: funcNode is a Setter.
    2. Let name be PropertyName : ? Ecmaify(funcNode.name).
    3. Set body to body0.
    4. Set prod to MethodDefinition : set name ( param ) { body }.
  9. Validate prod for any Early Error conditions. If early errors were found, then throw a SyntaxError or a ReferenceError exception, depending on the type of the error.
  10. Set functionObject.[[FormalParameters]] to params.
  11. Set functionObject.[[ECMAScriptCode]] to prod.

3.1.19Runtime Semantics: Delazify

Delazify is a new Runtime Semantics.

With parameter functionObject.

FunctionBody:FunctionStatementList
  1. If FunctionStatementList is a StatementList consisting of a single EmptyStatement that is tagged as being produced by funcNode in scope scope, then
    1. Assert: The current asserted scope is null.
    2. Set the current asserted scope to scope.
    3. Assert: funcNode is a LazyFunctionDeclaration, a LazyFunctionExpression, a LazyMethod, a LazyGetter, a LazySetter, or a LazyArrowExpression.
    4. Let contents be funcNode.contents.
    5. If funcNode is a LazyFunctionExpression, funcNode.name is not null, and contents.isFunctionNameCaptured is true, then
      1. Set scope to SynthesizeNamedLambdaScope(funcNode, scope).
    6. If funcNode is not a LazyArrowExpression, then
      1. Set scope to SynthesizeThisScope(funcNode, scope).
    7. If funcNode is not a LazyGetter, then
      1. Perform AddAssertedScopeTreeNode(contents.parameterScope, scope).
      2. Set scope to contents.parameterScope.
    8. Perform AddAssertedScopeTreeNode(contents.bodyScope, scope).
    9. Let delazifiedParams be the result of Delazify on the Parse Node that is functionObject.[[FormalParameters]] passing functionObject.
    10. Set the current asserted scope to contents.bodyScope.
    11. Let delazifiedBody be ? EcmaifyFunctionBody(funcNode).
    12. Perform ? ValidateAndUpdateFunctionObject(funcNode, functionObject, delazifiedBody, delazifiedParams).
    13. If funcNode is not a LazyGetter, then perform ? CheckAssertedScope(contents.parameterScope, delazifiedParams).
    14. Perform ? CheckAssertedScope(contents.bodyScope, delazifiedBody).
    15. If funcNode is a LazyArrowExpression, then
      1. Perform ? CheckThisCapture(contents.parameterScope, delazifiedParams).
      2. Perform ? CheckThisCapture(contents.bodyScope, delazifiedBody).
    16. Set the current asserted scope to null.
    17. Return FunctionBody : delazifiedBody.
  2. Else return FunctionBody.
FormalParameters:[empty]
  1. If FormalParameters is tagged as being produced by an AST node funcAst, then
    1. Assert: The current asserted scope is null.
    2. Set the current asserted scope to funcAst.contents.parameterScope.
    3. Let params be ? EcmaifyFormalParameters(funcAst.contents.params).
    4. Set the current asserted scope to null.
    5. Perform ? CheckFunctionLength(params, funcAst).
    6. Return params.
  2. Else return FormalParameters.
UniqueFormalParameters:FormalParameters
  1. Let delazifiedParams be the result of Delazify of FormalParameters passing null.
  2. Return UniqueFormalParameters : delazifiedParams.
ArrowParameters:CoverParenthesizedExpressionAndArrowParameterList
  1. If ArrowParameters is tagged as being produced by an AST node funcAst, then
    1. Set the current asserted scope to funcAst.contents.parameterScope.
    2. Let params be ? EcmaifyCoverArrowParameterList(funcAst.contents.params).
    3. Set the current asserted scope to null.
    4. Perform ? CheckFunctionLength(params, funcAst).
    5. Return params.
  2. Else return ArrowParameters.
PropertySetParameterList:FormalParameter
  1. If PropertySetParameterList is tagged as being produced by an AST node funcAst, then
    1. Set the current asserted scope to funcAst.contents.parameterScope.
    2. Let params be ? EcmaifyPropertySetParameterList(funcAst.contents.param).
    3. Set the current asserted scope to null.
    4. Return params.
  2. Else return PropertySetParameterList.

3.1.20Runtime Semantics: EvaluateBody

The runtime semantics of FunctionBody is modified as follows.

With parameters functionObject and List argumentsList.

FunctionBody:FunctionStatementList
  1. Let delazifiedBody be the Parse Node that is the result of Delazify of FunctionBody passing functionBody.
  2. If delazifiedBody is a different Parse Node from FunctionBody, then
    1. Return the result of EvaluateBody of the Parse Node that is functionObject.[[ECMAScriptCode]] passing functionObject and argumentsList.
  3. Else,
    1. Perform ? FunctionDeclarationInstantiation(functionObject, argumentsList).
    2. Return the result of evaluating FunctionStatementList.
GeneratorBody:FunctionBody
  1. Let delazifiedBody be the Parse Node that is the result of Delazify of FunctionBody passing functionObject.
  2. If delazifiedBody is a different Parse Node from FunctionBody, then
    1. Return the result of EvaluateBody of the Parse Node that is functionObject.[[ECMAScriptCode]] passing functionObject and argumentsList.
  3. Else,
    1. Perform ? FunctionDeclarationInstantiation(functionObject, argumentsList).
    2. Let G be ? OrdinaryCreateFromConstructor(functionObject, "%GeneratorPrototype%", « [[GeneratorState]], [[GeneratorContext]] »).
    3. Perform GeneratorStart(G, FunctionBody).
    4. Return Completion{[[Type]]: return, [[Value]]: G, [[Target]]: empty}.
AsyncFunctionBody:FunctionBody
  1. Let delazifiedBody be the Parse Node that is the result of Delazify of FunctionBody passing functionObject.
  2. If delazifiedBody is a different Parse Node from FunctionBody, then
    1. Return the result of EvaluateBody of the Parse Node that is functionObject.[[ECMAScriptCode]] passing functionObject and argumentsList.
  3. Else,
    1. Let promiseCapability be ! NewPromiseCapability(%Promise%).
    2. Let declResult be FunctionDeclarationInstantiation(functionObject, argumentsList).
    3. If declResult is not an abrupt completion, then
      1. Perform ! AsyncFunctionStart(promiseCapability, FunctionBody).
    4. Else declResult is an abrupt completion,
      1. Perform ! Call(promiseCapability.[[Reject]], undefined, «declResult.[[Value]]»).
    5. Return Completion{[[Type]]: return, [[Value]]: promiseCapability.[[Promise]], [[Target]]: empty}.

ACopyright & Software License

Copyright Notice

© 2018 Shu-yu Guo, David Teller, Ecma International

Software License

All Software contained in this document ("Software") is protected by copyright and is being made available under the "BSD License", included below. This Software may be subject to third party rights (rights from parties other than Ecma International), including patent rights, and no licenses under such third party rights are granted under this license even if the third party concerned is a member of Ecma International. SEE THE ECMA CODE OF CONDUCT IN PATENT MATTERS AVAILABLE AT https://ecma-international.org/memento/codeofconduct.htm FOR INFORMATION REGARDING THE LICENSING OF PATENT CLAIMS THAT ARE REQUIRED TO IMPLEMENT ECMA INTERNATIONAL STANDARDS.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

  1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
  2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
  3. Neither the name of the authors nor Ecma International may be used to endorse or promote products derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE ECMA INTERNATIONAL "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ECMA INTERNATIONAL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.