561 lines
24 KiB
Go
561 lines
24 KiB
Go
package estransforms
|
|
|
|
import (
|
|
"slices"
|
|
|
|
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/ast"
|
|
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/printer"
|
|
)
|
|
|
|
/**
|
|
* Gets whether a node is a `static {}` block containing only a single call to the `__setFunctionName` helper where that
|
|
* call's second argument is the value stored in the `assignedName` property of the block's `EmitNode`.
|
|
* @internal
|
|
*/
|
|
func isClassNamedEvaluationHelperBlock(emitContext *printer.EmitContext, node *ast.Node) bool {
|
|
if !ast.IsClassStaticBlockDeclaration(node) || len(node.AsClassStaticBlockDeclaration().Body.AsBlock().Statements.Nodes) != 1 {
|
|
return false
|
|
}
|
|
|
|
statement := node.AsClassStaticBlockDeclaration().Body.AsBlock().Statements.Nodes[0]
|
|
if ast.IsExpressionStatement(statement) {
|
|
expression := statement.AsExpressionStatement().Expression
|
|
if emitContext.IsCallToHelper(expression, "__setFunctionName") {
|
|
arguments := expression.AsCallExpression().Arguments
|
|
return len(arguments.Nodes) >= 2 &&
|
|
arguments.Nodes[1] == emitContext.AssignedName(node.AsNode())
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
/**
|
|
* Gets whether a `ClassLikeDeclaration` has a `static {}` block containing only a single call to the
|
|
* `__setFunctionName` helper.
|
|
* @internal
|
|
*/
|
|
func classHasExplicitlyAssignedName(emitContext *printer.EmitContext, node *ast.ClassLikeDeclaration) bool {
|
|
if assignedName := emitContext.AssignedName(node); assignedName != nil {
|
|
for _, member := range node.Members() {
|
|
if isClassNamedEvaluationHelperBlock(emitContext, member) {
|
|
return true
|
|
}
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
/**
|
|
* Gets whether a `ClassLikeDeclaration` has a declared name or contains a `static {}` block containing only a single
|
|
* call to the `__setFunctionName` helper.
|
|
* @internal
|
|
*/
|
|
func classHasDeclaredOrExplicitlyAssignedName(emitContext *printer.EmitContext, node *ast.ClassLikeDeclaration) bool {
|
|
return node.Name() != nil || classHasExplicitlyAssignedName(emitContext, node)
|
|
}
|
|
|
|
// Indicates whether a property name is the special `__proto__` property.
|
|
// Per the ECMA-262 spec, this only matters for property assignments whose name is
|
|
// the Identifier `__proto__`, or the string literal `"__proto__"`, but not for
|
|
// computed property names.
|
|
func isProtoSetter(node *ast.PropertyName) bool {
|
|
return ast.IsIdentifier(node) || ast.IsStringLiteral(node) && node.Text() == "__proto__"
|
|
}
|
|
|
|
type anonymousFunctionDefinition = ast.Node // ClassExpression | FunctionExpression | ArrowFunction
|
|
|
|
// Indicates whether an expression is an anonymous function definition.
|
|
//
|
|
// See https://tc39.es/ecma262/#sec-isanonymousfunctiondefinition
|
|
func isAnonymousFunctionDefinition(emitContext *printer.EmitContext, node *ast.Expression, cb func(*anonymousFunctionDefinition) bool) bool {
|
|
node = ast.SkipOuterExpressions(node, ast.OEKAll)
|
|
switch node.Kind {
|
|
case ast.KindClassExpression:
|
|
if classHasDeclaredOrExplicitlyAssignedName(emitContext, node) {
|
|
return false
|
|
}
|
|
break
|
|
case ast.KindFunctionExpression:
|
|
if node.AsFunctionExpression().Name() != nil {
|
|
return false
|
|
}
|
|
break
|
|
case ast.KindArrowFunction:
|
|
break
|
|
default:
|
|
return false
|
|
}
|
|
if cb != nil {
|
|
return cb(node)
|
|
}
|
|
return true
|
|
}
|
|
|
|
// Indicates whether a node is a potential source of an assigned name for a class, function, or arrow function.
|
|
func isNamedEvaluationSource(node *ast.Node) bool {
|
|
switch node.Kind {
|
|
case ast.KindPropertyAssignment:
|
|
return !isProtoSetter(node.AsPropertyAssignment().Name())
|
|
case ast.KindShorthandPropertyAssignment:
|
|
return node.AsShorthandPropertyAssignment().ObjectAssignmentInitializer != nil
|
|
case ast.KindVariableDeclaration:
|
|
return ast.IsIdentifier(node.AsVariableDeclaration().Name()) && node.AsVariableDeclaration().Initializer != nil
|
|
case ast.KindParameter:
|
|
return ast.IsIdentifier(node.AsParameterDeclaration().Name()) && node.AsParameterDeclaration().Initializer != nil && node.AsParameterDeclaration().DotDotDotToken == nil
|
|
case ast.KindBindingElement:
|
|
return ast.IsIdentifier(node.AsBindingElement().Name()) && node.AsBindingElement().Initializer != nil && node.AsBindingElement().DotDotDotToken == nil
|
|
case ast.KindPropertyDeclaration:
|
|
return node.AsPropertyDeclaration().Initializer != nil
|
|
case ast.KindBinaryExpression:
|
|
switch node.AsBinaryExpression().OperatorToken.Kind {
|
|
case ast.KindEqualsToken, ast.KindAmpersandAmpersandEqualsToken, ast.KindBarBarEqualsToken, ast.KindQuestionQuestionEqualsToken:
|
|
return ast.IsIdentifier(node.AsBinaryExpression().Left)
|
|
}
|
|
break
|
|
case ast.KindExportAssignment:
|
|
return true
|
|
}
|
|
return false
|
|
}
|
|
|
|
func isNamedEvaluation(emitContext *printer.EmitContext, node *ast.Node) bool {
|
|
return isNamedEvaluationAnd(emitContext, node, nil)
|
|
}
|
|
|
|
func isNamedEvaluationAnd(emitContext *printer.EmitContext, node *ast.Node, cb func(*anonymousFunctionDefinition) bool) bool {
|
|
if !isNamedEvaluationSource(node) {
|
|
return false
|
|
}
|
|
switch node.Kind {
|
|
case ast.KindShorthandPropertyAssignment:
|
|
return isAnonymousFunctionDefinition(emitContext, node.AsShorthandPropertyAssignment().ObjectAssignmentInitializer, cb)
|
|
case ast.KindPropertyAssignment, ast.KindVariableDeclaration, ast.KindParameter, ast.KindBindingElement, ast.KindPropertyDeclaration:
|
|
return isAnonymousFunctionDefinition(emitContext, node.Initializer(), cb)
|
|
case ast.KindBinaryExpression:
|
|
return isAnonymousFunctionDefinition(emitContext, node.AsBinaryExpression().Right, cb)
|
|
case ast.KindExportAssignment:
|
|
return isAnonymousFunctionDefinition(emitContext, node.AsExportAssignment().Expression, cb)
|
|
default:
|
|
panic("Unhandled case in isNamedEvaluation")
|
|
}
|
|
}
|
|
|
|
// Gets a string literal to use as the assigned name of an anonymous class or function declaration.
|
|
func getAssignedNameOfIdentifier(emitContext *printer.EmitContext, name *ast.IdentifierNode, expression *ast.Node /*WrappedExpression<AnonymousFunctionDefinition>*/) *ast.StringLiteralNode {
|
|
original := emitContext.MostOriginal(ast.SkipOuterExpressions(expression, ast.OEKAll))
|
|
if (ast.IsClassDeclaration(original) || ast.IsFunctionDeclaration(original)) &&
|
|
original.Name() == nil && ast.HasSyntacticModifier(original, ast.ModifierFlagsDefault) {
|
|
return emitContext.Factory.NewStringLiteral("default")
|
|
}
|
|
return emitContext.Factory.NewStringLiteralFromNode(name)
|
|
}
|
|
|
|
func getAssignedNameOfPropertyName(emitContext *printer.EmitContext, name *ast.PropertyName, assignedNameText string) (assignedName *ast.Expression, updatedName *ast.PropertyName) {
|
|
factory := emitContext.Factory
|
|
if len(assignedNameText) > 0 {
|
|
assignedName := factory.NewStringLiteral(assignedNameText)
|
|
return assignedName, name
|
|
}
|
|
|
|
if ast.IsPropertyNameLiteral(name) || ast.IsPrivateIdentifier(name) {
|
|
assignedName := factory.NewStringLiteralFromNode(name)
|
|
return assignedName, name
|
|
}
|
|
|
|
expression := name.Expression()
|
|
if ast.IsPropertyNameLiteral(expression) && !ast.IsIdentifier(expression) {
|
|
assignedName := factory.NewStringLiteralFromNode(expression)
|
|
return assignedName, name
|
|
}
|
|
|
|
if !ast.IsComputedPropertyName(expression) {
|
|
panic("Expected computed property name")
|
|
}
|
|
|
|
assignedName = factory.NewGeneratedNameForNode(name)
|
|
emitContext.AddVariableDeclaration(assignedName)
|
|
|
|
key := factory.NewPropKeyHelper(expression)
|
|
assignment := factory.NewAssignmentExpression(assignedName, key)
|
|
updatedName = factory.UpdateComputedPropertyName(name.AsComputedPropertyName(), assignment)
|
|
return assignedName, updatedName
|
|
}
|
|
|
|
// Creates a class `static {}` block used to dynamically set the name of a class.
|
|
//
|
|
// The assignedName parameter is the expression used to resolve the assigned name at runtime. This expression should not produce
|
|
// side effects.
|
|
// The thisExpression parameter overrides the expression to use for the actual `this` reference. This can be used to provide an
|
|
// expression that has already had its `EmitFlags` set or may have been tracked to prevent substitution.
|
|
func createClassNamedEvaluationHelperBlock(emitContext *printer.EmitContext, assignedName *ast.Expression, thisExpression *ast.Expression) *ast.Node {
|
|
// produces:
|
|
//
|
|
// static { __setFunctionName(this, "C"); }
|
|
//
|
|
|
|
if thisExpression == nil {
|
|
thisExpression = emitContext.Factory.NewThisExpression()
|
|
}
|
|
|
|
factory := emitContext.Factory
|
|
expression := factory.NewSetFunctionNameHelper(thisExpression, assignedName, "" /*prefix*/)
|
|
statement := factory.NewExpressionStatement(expression)
|
|
body := factory.NewBlock(factory.NewNodeList([]*ast.Statement{statement}), false /*multiLine*/)
|
|
block := factory.NewClassStaticBlockDeclaration(nil /*modifiers*/, body)
|
|
|
|
// We use `emitNode.assignedName` to indicate this is a NamedEvaluation helper block
|
|
// and to stash the expression used to resolve the assigned name.
|
|
emitContext.SetAssignedName(block, assignedName)
|
|
return block.AsNode()
|
|
}
|
|
|
|
// Injects a class `static {}` block used to dynamically set the name of a class, if one does not already exist.
|
|
func injectClassNamedEvaluationHelperBlockIfMissing(
|
|
emitContext *printer.EmitContext,
|
|
node *ast.ClassLikeDeclaration,
|
|
assignedName *ast.Expression,
|
|
thisExpression *ast.Expression,
|
|
) *ast.ClassLikeDeclaration {
|
|
// given:
|
|
//
|
|
// let C = class {
|
|
// };
|
|
//
|
|
// produces:
|
|
//
|
|
// let C = class {
|
|
// static { __setFunctionName(this, "C"); }
|
|
// };
|
|
|
|
// NOTE: If the class has a `_classThis` assignment block, this helper will be injected after that block.
|
|
|
|
if classHasExplicitlyAssignedName(emitContext, node) {
|
|
return node
|
|
}
|
|
|
|
factory := emitContext.Factory
|
|
namedEvaluationBlock := createClassNamedEvaluationHelperBlock(emitContext, assignedName, thisExpression)
|
|
if node.Name() != nil {
|
|
emitContext.SetSourceMapRange(namedEvaluationBlock.Body().AsBlock().Statements.Nodes[0], node.Name().Loc)
|
|
}
|
|
|
|
insertionIndex := slices.IndexFunc(node.Members(), func(n *ast.Node) bool {
|
|
return isClassThisAssignmentBlock(emitContext, n)
|
|
}) + 1
|
|
leading := slices.Clone(node.Members()[:insertionIndex])
|
|
trailing := slices.Clone(node.Members()[insertionIndex:])
|
|
|
|
var members []*ast.ClassElement
|
|
members = append(members, leading...)
|
|
members = append(members, namedEvaluationBlock)
|
|
members = append(members, trailing...)
|
|
membersList := factory.NewNodeList(members)
|
|
membersList.Loc = node.MemberList().Loc
|
|
|
|
if ast.IsClassDeclaration(node) {
|
|
node = factory.UpdateClassDeclaration(
|
|
node.AsClassDeclaration(),
|
|
node.Modifiers(),
|
|
node.Name(),
|
|
node.TypeParameterList(),
|
|
node.AsClassDeclaration().HeritageClauses,
|
|
membersList,
|
|
)
|
|
} else {
|
|
node = factory.UpdateClassExpression(
|
|
node.AsClassExpression(),
|
|
node.Modifiers(),
|
|
node.Name(),
|
|
node.TypeParameterList(),
|
|
node.AsClassExpression().HeritageClauses,
|
|
membersList,
|
|
)
|
|
}
|
|
|
|
emitContext.SetAssignedName(node, assignedName)
|
|
return node
|
|
}
|
|
|
|
func finishTransformNamedEvaluation(
|
|
emitContext *printer.EmitContext,
|
|
expression *ast.Node, // WrappedExpression<AnonymousFunctionDefinition>,
|
|
assignedName *ast.Expression,
|
|
ignoreEmptyStringLiteral bool,
|
|
) *ast.Expression {
|
|
if ignoreEmptyStringLiteral && ast.IsStringLiteral(assignedName) && len(assignedName.Text()) == 0 {
|
|
return expression
|
|
}
|
|
|
|
factory := emitContext.Factory
|
|
innerExpression := ast.SkipOuterExpressions(expression, ast.OEKAll)
|
|
|
|
var updatedExpression *ast.Expression
|
|
if ast.IsClassExpression(innerExpression) {
|
|
updatedExpression = injectClassNamedEvaluationHelperBlockIfMissing(emitContext, innerExpression, assignedName, nil /*thisExpression*/)
|
|
} else {
|
|
updatedExpression = factory.NewSetFunctionNameHelper(innerExpression, assignedName, "" /*prefix*/)
|
|
}
|
|
|
|
return factory.RestoreOuterExpressions(expression, updatedExpression, ast.OEKAll)
|
|
}
|
|
|
|
func transformNamedEvaluationOfPropertyAssignment(context *printer.EmitContext, node *ast.PropertyAssignment /*NamedEvaluation & PropertyAssignment*/, ignoreEmptyStringLiteral bool, assignedNameText string) *ast.Expression {
|
|
// 13.2.5.5 RS: PropertyDefinitionEvaluation
|
|
// PropertyAssignment : PropertyName `:` AssignmentExpression
|
|
// ...
|
|
// 5. If IsAnonymousFunctionDefinition(|AssignmentExpression|) is *true* and _isProtoSetter_ is *false*, then
|
|
// a. Let _popValue_ be ? NamedEvaluation of |AssignmentExpression| with argument _propKey_.
|
|
// ...
|
|
|
|
factory := context.Factory
|
|
assignedName, name := getAssignedNameOfPropertyName(context, node.Name(), assignedNameText)
|
|
initializer := finishTransformNamedEvaluation(context, node.Initializer, assignedName, ignoreEmptyStringLiteral)
|
|
return factory.UpdatePropertyAssignment(node, nil /*modifiers*/, name, nil /*postfixToken*/, nil /*typeNode*/, initializer)
|
|
}
|
|
|
|
func transformNamedEvaluationOfShorthandAssignmentProperty(emitContext *printer.EmitContext, node *ast.ShorthandPropertyAssignment /*NamedEvaluation & ShorthandPropertyAssignment*/, ignoreEmptyStringLiteral bool, assignedNameText string) *ast.Expression {
|
|
// 13.15.5.3 RS: PropertyDestructuringAssignmentEvaluation
|
|
// AssignmentProperty : IdentifierReference Initializer?
|
|
// ...
|
|
// 4. If |Initializer?| is present and _v_ is *undefined*, then
|
|
// a. If IsAnonymousFunctionDefinition(|Initializer|) is *true*, then
|
|
// i. Set _v_ to ? NamedEvaluation of |Initializer| with argument _P_.
|
|
// ...
|
|
|
|
factory := emitContext.Factory
|
|
var assignedName *ast.Expression
|
|
if len(assignedNameText) > 0 {
|
|
assignedName = factory.NewStringLiteral(assignedNameText)
|
|
} else {
|
|
assignedName = getAssignedNameOfIdentifier(emitContext, node.Name(), node.ObjectAssignmentInitializer)
|
|
}
|
|
objectAssignmentInitializer := finishTransformNamedEvaluation(emitContext, node.ObjectAssignmentInitializer, assignedName, ignoreEmptyStringLiteral)
|
|
return factory.UpdateShorthandPropertyAssignment(
|
|
node,
|
|
nil, /*modifiers*/
|
|
node.Name(),
|
|
nil, /*postfixToken*/
|
|
nil, /*typeNode*/
|
|
node.EqualsToken,
|
|
objectAssignmentInitializer,
|
|
)
|
|
}
|
|
|
|
func transformNamedEvaluationOfVariableDeclaration(emitContext *printer.EmitContext, node *ast.VariableDeclaration /*NamedEvaluation & VariableDeclaration*/, ignoreEmptyStringLiteral bool, assignedNameText string) *ast.Expression {
|
|
// 14.3.1.2 RS: Evaluation
|
|
// LexicalBinding : BindingIdentifier Initializer
|
|
// ...
|
|
// 3. If IsAnonymousFunctionDefinition(|Initializer|) is *true*, then
|
|
// a. Let _value_ be ? NamedEvaluation of |Initializer| with argument _bindingId_.
|
|
// ...
|
|
//
|
|
// 14.3.2.1 RS: Evaluation
|
|
// VariableDeclaration : BindingIdentifier Initializer
|
|
// ...
|
|
// 3. If IsAnonymousFunctionDefinition(|Initializer|) is *true*, then
|
|
// a. Let _value_ be ? NamedEvaluation of |Initializer| with argument _bindingId_.
|
|
// ...
|
|
|
|
factory := emitContext.Factory
|
|
var assignedName *ast.Expression
|
|
if len(assignedNameText) > 0 {
|
|
assignedName = factory.NewStringLiteral(assignedNameText)
|
|
} else {
|
|
assignedName = getAssignedNameOfIdentifier(emitContext, node.Name(), node.Initializer)
|
|
}
|
|
initializer := finishTransformNamedEvaluation(emitContext, node.Initializer, assignedName, ignoreEmptyStringLiteral)
|
|
return factory.UpdateVariableDeclaration(
|
|
node,
|
|
node.Name(),
|
|
nil, /*exclamationToken*/
|
|
nil, /*typeNode*/
|
|
initializer,
|
|
)
|
|
}
|
|
|
|
func transformNamedEvaluationOfParameterDeclaration(emitContext *printer.EmitContext, node *ast.ParameterDeclaration /*NamedEvaluation & ParameterDeclaration*/, ignoreEmptyStringLiteral bool, assignedNameText string) *ast.Expression {
|
|
// 8.6.3 RS: IteratorBindingInitialization
|
|
// SingleNameBinding : BindingIdentifier Initializer?
|
|
// ...
|
|
// 5. If |Initializer| is present and _v_ is *undefined*, then
|
|
// a. If IsAnonymousFunctionDefinition(|Initializer|) is *true*, then
|
|
// i. Set _v_ to ? NamedEvaluation of |Initializer| with argument _bindingId_.
|
|
// ...
|
|
//
|
|
// 14.3.3.3 RS: KeyedBindingInitialization
|
|
// SingleNameBinding : BindingIdentifier Initializer?
|
|
// ...
|
|
// 4. If |Initializer| is present and _v_ is *undefined*, then
|
|
// a. If IsAnonymousFunctionDefinition(|Initializer|) is *true*, then
|
|
// i. Set _v_ to ? NamedEvaluation of |Initializer| with argument _bindingId_.
|
|
// ...
|
|
|
|
factory := emitContext.Factory
|
|
var assignedName *ast.Expression
|
|
if len(assignedNameText) > 0 {
|
|
assignedName = factory.NewStringLiteral(assignedNameText)
|
|
} else {
|
|
assignedName = getAssignedNameOfIdentifier(emitContext, node.Name(), node.Initializer)
|
|
}
|
|
initializer := finishTransformNamedEvaluation(emitContext, node.Initializer, assignedName, ignoreEmptyStringLiteral)
|
|
return factory.UpdateParameterDeclaration(
|
|
node,
|
|
nil, /*modifiers*/
|
|
node.DotDotDotToken,
|
|
node.Name(),
|
|
nil, /*questionToken*/
|
|
nil, /*typeNode*/
|
|
initializer,
|
|
)
|
|
}
|
|
|
|
func transformNamedEvaluationOfBindingElement(emitContext *printer.EmitContext, node *ast.BindingElement /*NamedEvaluation & BindingElement*/, ignoreEmptyStringLiteral bool, assignedNameText string) *ast.Expression {
|
|
// 8.6.3 RS: IteratorBindingInitialization
|
|
// SingleNameBinding : BindingIdentifier Initializer?
|
|
// ...
|
|
// 5. If |Initializer| is present and _v_ is *undefined*, then
|
|
// a. If IsAnonymousFunctionDefinition(|Initializer|) is *true*, then
|
|
// i. Set _v_ to ? NamedEvaluation of |Initializer| with argument _bindingId_.
|
|
// ...
|
|
//
|
|
// 14.3.3.3 RS: KeyedBindingInitialization
|
|
// SingleNameBinding : BindingIdentifier Initializer?
|
|
// ...
|
|
// 4. If |Initializer| is present and _v_ is *undefined*, then
|
|
// a. If IsAnonymousFunctionDefinition(|Initializer|) is *true*, then
|
|
// i. Set _v_ to ? NamedEvaluation of |Initializer| with argument _bindingId_.
|
|
// ...
|
|
|
|
factory := emitContext.Factory
|
|
var assignedName *ast.Expression
|
|
if len(assignedNameText) > 0 {
|
|
assignedName = factory.NewStringLiteral(assignedNameText)
|
|
} else {
|
|
assignedName = getAssignedNameOfIdentifier(emitContext, node.Name(), node.Initializer)
|
|
}
|
|
initializer := finishTransformNamedEvaluation(emitContext, node.Initializer, assignedName, ignoreEmptyStringLiteral)
|
|
return factory.UpdateBindingElement(
|
|
node,
|
|
node.DotDotDotToken,
|
|
node.PropertyName,
|
|
node.Name(),
|
|
initializer,
|
|
)
|
|
}
|
|
|
|
func transformNamedEvaluationOfPropertyDeclaration(emitContext *printer.EmitContext, node *ast.PropertyDeclaration /*NamedEvaluation & PropertyDeclaration*/, ignoreEmptyStringLiteral bool, assignedNameText string) *ast.Expression {
|
|
// 10.2.1.3 RS: EvaluateBody
|
|
// Initializer : `=` AssignmentExpression
|
|
// ...
|
|
// 3. If IsAnonymousFunctionDefinition(|AssignmentExpression|) is *true*, then
|
|
// a. Let _value_ be ? NamedEvaluation of |Initializer| with argument _functionObject_.[[ClassFieldInitializerName]].
|
|
// ...
|
|
|
|
factory := emitContext.Factory
|
|
assignedName, name := getAssignedNameOfPropertyName(emitContext, node.Name(), assignedNameText)
|
|
initializer := finishTransformNamedEvaluation(emitContext, node.Initializer, assignedName, ignoreEmptyStringLiteral)
|
|
return factory.UpdatePropertyDeclaration(
|
|
node,
|
|
node.Modifiers(),
|
|
name,
|
|
nil, /*postfixToken*/
|
|
nil, /*typeNode*/
|
|
initializer,
|
|
)
|
|
}
|
|
|
|
func transformNamedEvaluationOfAssignmentExpression(emitContext *printer.EmitContext, node *ast.BinaryExpression /*NamedEvaluation & BinaryExpression*/, ignoreEmptyStringLiteral bool, assignedNameText string) *ast.Expression {
|
|
// 13.15.2 RS: Evaluation
|
|
// AssignmentExpression : LeftHandSideExpression `=` AssignmentExpression
|
|
// 1. If |LeftHandSideExpression| is neither an |ObjectLiteral| nor an |ArrayLiteral|, then
|
|
// a. Let _lref_ be ? Evaluation of |LeftHandSideExpression|.
|
|
// b. If IsAnonymousFunctionDefinition(|AssignmentExpression|) and IsIdentifierRef of |LeftHandSideExpression| are both *true*, then
|
|
// i. Let _rval_ be ? NamedEvaluation of |AssignmentExpression| with argument _lref_.[[ReferencedName]].
|
|
// ...
|
|
//
|
|
// AssignmentExpression : LeftHandSideExpression `&&=` AssignmentExpression
|
|
// ...
|
|
// 5. If IsAnonymousFunctionDefinition(|AssignmentExpression|) is *true* and IsIdentifierRef of |LeftHandSideExpression| is *true*, then
|
|
// a. Let _rval_ be ? NamedEvaluation of |AssignmentExpression| with argument _lref_.[[ReferencedName]].
|
|
// ...
|
|
//
|
|
// AssignmentExpression : LeftHandSideExpression `||=` AssignmentExpression
|
|
// ...
|
|
// 5. If IsAnonymousFunctionDefinition(|AssignmentExpression|) is *true* and IsIdentifierRef of |LeftHandSideExpression| is *true*, then
|
|
// a. Let _rval_ be ? NamedEvaluation of |AssignmentExpression| with argument _lref_.[[ReferencedName]].
|
|
// ...
|
|
//
|
|
// AssignmentExpression : LeftHandSideExpression `??=` AssignmentExpression
|
|
// ...
|
|
// 4. If IsAnonymousFunctionDefinition(|AssignmentExpression|) is *true* and IsIdentifierRef of |LeftHandSideExpression| is *true*, then
|
|
// a. Let _rval_ be ? NamedEvaluation of |AssignmentExpression| with argument _lref_.[[ReferencedName]].
|
|
// ...
|
|
|
|
factory := emitContext.Factory
|
|
var assignedName *ast.Expression
|
|
if len(assignedNameText) > 0 {
|
|
assignedName = factory.NewStringLiteral(assignedNameText)
|
|
} else {
|
|
assignedName = getAssignedNameOfIdentifier(emitContext, node.Left, node.Right)
|
|
}
|
|
right := finishTransformNamedEvaluation(emitContext, node.Right, assignedName, ignoreEmptyStringLiteral)
|
|
return factory.UpdateBinaryExpression(
|
|
node,
|
|
nil, /*modifiers*/
|
|
node.Left,
|
|
nil, /*typeNode*/
|
|
node.OperatorToken,
|
|
right,
|
|
)
|
|
}
|
|
|
|
func transformNamedEvaluationOfExportAssignment(emitContext *printer.EmitContext, node *ast.ExportAssignment /*NamedEvaluation & ExportAssignment*/, ignoreEmptyStringLiteral bool, assignedNameText string) *ast.Expression {
|
|
// 16.2.3.7 RS: Evaluation
|
|
// ExportDeclaration : `export` `default` AssignmentExpression `;`
|
|
// 1. If IsAnonymousFunctionDefinition(|AssignmentExpression|) is *true*, then
|
|
// a. Let _value_ be ? NamedEvaluation of |AssignmentExpression| with argument `"default"`.
|
|
// ...
|
|
|
|
// NOTE: Since emit for `export =` translates to `module.exports = ...`, the assigned name of the class or function
|
|
// is `""`.
|
|
|
|
factory := emitContext.Factory
|
|
var assignedName *ast.Expression
|
|
if len(assignedNameText) > 0 {
|
|
assignedName = factory.NewStringLiteral(assignedNameText)
|
|
} else {
|
|
assignedName = factory.NewStringLiteral("")
|
|
}
|
|
expression := finishTransformNamedEvaluation(emitContext, node.Expression, assignedName, ignoreEmptyStringLiteral)
|
|
return factory.UpdateExportAssignment(
|
|
node,
|
|
nil, /*modifiers*/
|
|
nil, /*typeNode*/
|
|
expression,
|
|
)
|
|
}
|
|
|
|
// Performs a shallow transformation of a `NamedEvaluation` node, such that a valid name will be assigned.
|
|
func transformNamedEvaluation(context *printer.EmitContext, node *ast.Node /*NamedEvaluation*/, ignoreEmptyStringLiteral bool, assignedName string) *ast.Expression {
|
|
switch node.Kind {
|
|
case ast.KindPropertyAssignment:
|
|
return transformNamedEvaluationOfPropertyAssignment(context, node.AsPropertyAssignment(), ignoreEmptyStringLiteral, assignedName)
|
|
case ast.KindShorthandPropertyAssignment:
|
|
return transformNamedEvaluationOfShorthandAssignmentProperty(context, node.AsShorthandPropertyAssignment(), ignoreEmptyStringLiteral, assignedName)
|
|
case ast.KindVariableDeclaration:
|
|
return transformNamedEvaluationOfVariableDeclaration(context, node.AsVariableDeclaration(), ignoreEmptyStringLiteral, assignedName)
|
|
case ast.KindParameter:
|
|
return transformNamedEvaluationOfParameterDeclaration(context, node.AsParameterDeclaration(), ignoreEmptyStringLiteral, assignedName)
|
|
case ast.KindBindingElement:
|
|
return transformNamedEvaluationOfBindingElement(context, node.AsBindingElement(), ignoreEmptyStringLiteral, assignedName)
|
|
case ast.KindPropertyDeclaration:
|
|
return transformNamedEvaluationOfPropertyDeclaration(context, node.AsPropertyDeclaration(), ignoreEmptyStringLiteral, assignedName)
|
|
case ast.KindBinaryExpression:
|
|
return transformNamedEvaluationOfAssignmentExpression(context, node.AsBinaryExpression(), ignoreEmptyStringLiteral, assignedName)
|
|
case ast.KindExportAssignment:
|
|
return transformNamedEvaluationOfExportAssignment(context, node.AsExportAssignment(), ignoreEmptyStringLiteral, assignedName)
|
|
default:
|
|
panic("Unhandled case in transformNamedEvaluation")
|
|
}
|
|
}
|