Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 6 additions & 13 deletions tsc/internal/transformers/estransforms/definitions.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,11 @@ var (
// 2024: no new downlevel syntax
// 2023: no new downlevel syntax
// 2022: class static blocks and class fields are handled by newClassFieldsTransformer
NewES2021Transformer = transformers.Chain(NewESNextTransformer, newLogicalAssignmentTransformer)
NewES2020Transformer = transformers.Chain(NewES2021Transformer, newNullishCoalescingTransformer, newOptionalChainTransformer)
NewES2019Transformer = transformers.Chain(NewES2020Transformer, newOptionalCatchTransformer)
NewES2018Transformer = transformers.Chain(NewES2019Transformer, newObjectRestSpreadTransformer, newforawaitTransformer, newTaggedTemplateLiftRestrictionTransformer)
// Local syntax lowerings share one target-aware traversal. Decorators and class
// fields must run first because they can generate syntax that needs lowering.
NewES2021Transformer = transformers.Chain(NewESNextTransformer, newSyntaxTransformer)
NewES2018Transformer = transformers.Chain(NewES2021Transformer, newObjectRestSpreadTransformer, newforawaitTransformer, newTaggedTemplateLiftRestrictionTransformer)
NewES2017Transformer = transformers.Chain(NewES2018Transformer, newAsyncTransformer)
NewES2016Transformer = transformers.Chain(NewES2017Transformer, newExponentiationTransformer)
)

func GetESTransformer(opts *transformers.TransformOptions) *transformers.Transformer {
Expand All @@ -28,17 +27,11 @@ func GetESTransformer(opts *transformers.TransformOptions) *transformers.Transfo
return esDecoratorAndClassFields(opts)
case core.ScriptTargetES2026, core.ScriptTargetES2025, core.ScriptTargetES2024, core.ScriptTargetES2023, core.ScriptTargetES2022, core.ScriptTargetES2021:
return NewESNextTransformer(opts)
case core.ScriptTargetES2020:
case core.ScriptTargetES2020, core.ScriptTargetES2019, core.ScriptTargetES2018:
return NewES2021Transformer(opts)
case core.ScriptTargetES2019:
return NewES2020Transformer(opts)
case core.ScriptTargetES2018:
return NewES2019Transformer(opts)
case core.ScriptTargetES2017:
return NewES2018Transformer(opts)
case core.ScriptTargetES2016:
return NewES2017Transformer(opts)
default: // other, older, option, transform maximally
return NewES2016Transformer(opts)
return NewES2017Transformer(opts)
}
}
36 changes: 2 additions & 34 deletions tsc/internal/transformers/estransforms/exponentiation.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,36 +2,9 @@ package estransforms

import (
"github.com/microsoft/TypeScript/tsc/internal/ast"
"github.com/microsoft/TypeScript/tsc/internal/transformers"
)

type exponentiationTransformer struct {
transformers.Transformer
}

func (ch *exponentiationTransformer) visit(node *ast.Node) *ast.Node {
if node.SubtreeFacts()&ast.SubtreeContainsExponentiationOperator == 0 {
return node
}
switch node.Kind {
case ast.KindBinaryExpression:
return ch.visitBinaryExpression(node.AsBinaryExpression())
default:
return ch.Visitor().VisitEachChild(node)
}
}

func (ch *exponentiationTransformer) visitBinaryExpression(node *ast.BinaryExpression) *ast.Node {
switch node.OperatorToken.Kind {
case ast.KindAsteriskAsteriskEqualsToken:
return ch.visitExponentiationAssignmentExpression(node)
case ast.KindAsteriskAsteriskToken:
return ch.visitExponentiationExpression(node)
}
return ch.Visitor().VisitEachChild(node.AsNode())
}

func (ch *exponentiationTransformer) visitExponentiationAssignmentExpression(node *ast.BinaryExpression) *ast.Node {
func (ch *syntaxTransformer) visitExponentiationAssignmentExpression(node *ast.BinaryExpression) *ast.Node {
var target *ast.Node
var value *ast.Node
left := ch.Visitor().VisitNode(node.Left)
Expand Down Expand Up @@ -76,15 +49,10 @@ func (ch *exponentiationTransformer) visitExponentiationAssignmentExpression(nod
return result
}

func (ch *exponentiationTransformer) visitExponentiationExpression(node *ast.BinaryExpression) *ast.Node {
func (ch *syntaxTransformer) visitExponentiationExpression(node *ast.BinaryExpression) *ast.Node {
left := ch.Visitor().VisitNode(node.Left)
right := ch.Visitor().VisitNode(node.Right)
result := ch.Factory().NewGlobalMethodCall("Math", "pow", []*ast.Node{left, right})
result.Loc = node.Loc
return result
}

func newExponentiationTransformer(opts *transformers.TransformOptions) *transformers.Transformer {
tx := &exponentiationTransformer{}
return tx.NewTransformer(tx.visit, opts.Context)
}
25 changes: 2 additions & 23 deletions tsc/internal/transformers/estransforms/logicalassignment.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,7 @@ import (
"github.com/microsoft/TypeScript/tsc/internal/transformers"
)

type logicalAssignmentTransformer struct {
transformers.Transformer
}

func (ch *logicalAssignmentTransformer) visit(node *ast.Node) *ast.Node {
if node.SubtreeFacts()&ast.SubtreeContainsLogicalAssignments == 0 {
return node
}
switch node.Kind {
case ast.KindBinaryExpression:
return ch.visitBinaryExpression(node.AsBinaryExpression())
default:
return ch.Visitor().VisitEachChild(node)
}
}

func (ch *logicalAssignmentTransformer) visitBinaryExpression(node *ast.BinaryExpression) *ast.Node {
func (ch *syntaxTransformer) visitLogicalAssignment(node *ast.BinaryExpression) *ast.Node {
var nonAssignmentOperator ast.Kind
switch node.OperatorToken.Kind {
case ast.KindBarBarEqualsToken:
Expand All @@ -31,7 +15,7 @@ func (ch *logicalAssignmentTransformer) visitBinaryExpression(node *ast.BinaryEx
case ast.KindQuestionQuestionEqualsToken:
nonAssignmentOperator = ast.KindQuestionQuestionToken
default:
return ch.Visitor().VisitEachChild(node.AsNode())
panic("Expected a logical assignment")
}

left := ast.SkipParentheses(ch.Visitor().VisitNode(node.Left))
Expand Down Expand Up @@ -106,8 +90,3 @@ func (ch *logicalAssignmentTransformer) visitBinaryExpression(node *ast.BinaryEx
),
)
}

func newLogicalAssignmentTransformer(opts *transformers.TransformOptions) *transformers.Transformer {
tx := &logicalAssignmentTransformer{}
return tx.NewTransformer(tx.visit, opts.Context)
}
53 changes: 13 additions & 40 deletions tsc/internal/transformers/estransforms/nullishcoalescing.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,45 +5,18 @@ import (
"github.com/microsoft/TypeScript/tsc/internal/transformers"
)

type nullishCoalescingTransformer struct {
transformers.Transformer
}

func (ch *nullishCoalescingTransformer) visit(node *ast.Node) *ast.Node {
if node.SubtreeFacts()&ast.SubtreeContainsNullishCoalescing == 0 {
return node
}
switch node.Kind {
case ast.KindBinaryExpression:
return ch.visitBinaryExpression(node.AsBinaryExpression())
default:
return ch.Visitor().VisitEachChild(node)
}
}

func (ch *nullishCoalescingTransformer) visitBinaryExpression(node *ast.BinaryExpression) *ast.Node {
switch node.OperatorToken.Kind {
case ast.KindQuestionQuestionToken:
left := ch.Visitor().VisitNode(node.Left)
right := left
if !transformers.IsSimpleCopiableExpression(left) {
right = ch.Factory().NewTempVariable()
ch.EmitContext().AddVariableDeclaration(right)
left = ch.Factory().NewAssignmentExpression(right, left)
}
return ch.Factory().NewConditionalExpression(
createNotNullCondition(ch.EmitContext(), left, right, false),
ch.Factory().NewToken(ast.KindQuestionToken),
right,
ch.Factory().NewToken(ast.KindColonToken),
ch.Visitor().VisitNode(node.Right),
)
default:
return ch.Visitor().VisitEachChild(node.AsNode())
func (ch *syntaxTransformer) lowerNullishCoalescing(left *ast.Node, fallback *ast.Node) *ast.Node {
value := left
if !transformers.IsSimpleCopiableExpression(left) {
value = ch.Factory().NewTempVariable()
ch.EmitContext().AddVariableDeclaration(value)
left = ch.Factory().NewAssignmentExpression(value, left)
}
}

func newNullishCoalescingTransformer(opts *transformers.TransformOptions) *transformers.Transformer {
tx := &nullishCoalescingTransformer{}
return tx.NewTransformer(tx.visit, opts.Context)
return ch.Factory().NewConditionalExpression(
createNotNullCondition(ch.EmitContext(), left, value, false),
ch.Factory().NewToken(ast.KindQuestionToken),
value,
ch.Factory().NewToken(ast.KindColonToken),
fallback,
)
}
24 changes: 1 addition & 23 deletions tsc/internal/transformers/estransforms/optionalcatch.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,9 @@ package estransforms

import (
"github.com/microsoft/TypeScript/tsc/internal/ast"
"github.com/microsoft/TypeScript/tsc/internal/transformers"
)

type optionalCatchTransformer struct {
transformers.Transformer
}

func (ch *optionalCatchTransformer) visit(node *ast.Node) *ast.Node {
if node.SubtreeFacts()&ast.SubtreeContainsMissingCatchClauseVariable == 0 {
return node
}
switch node.Kind {
case ast.KindCatchClause:
return ch.visitCatchClause(node.AsCatchClause())
default:
return ch.Visitor().VisitEachChild(node)
}
}

func (ch *optionalCatchTransformer) visitCatchClause(node *ast.CatchClause) *ast.Node {
func (ch *syntaxTransformer) visitCatchClause(node *ast.CatchClause) *ast.Node {
if node.VariableDeclaration == nil {
return ch.Factory().NewCatchClause(
ch.Factory().NewVariableDeclaration(ch.Factory().NewTempVariable(), nil, nil, nil),
Expand All @@ -30,8 +13,3 @@ func (ch *optionalCatchTransformer) visitCatchClause(node *ast.CatchClause) *ast
}
return ch.Visitor().VisitEachChild(node.AsNode())
}

func newOptionalCatchTransformer(opts *transformers.TransformOptions) *transformers.Transformer {
tx := &optionalCatchTransformer{}
return tx.NewTransformer(tx.visit, opts.Context)
}
41 changes: 6 additions & 35 deletions tsc/internal/transformers/estransforms/optionalchain.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,31 +7,7 @@ import (
"github.com/microsoft/TypeScript/tsc/internal/transformers"
)

type optionalChainTransformer struct {
transformers.Transformer
}

func (ch *optionalChainTransformer) visit(node *ast.Node) *ast.Node {
if node.SubtreeFacts()&ast.SubtreeContainsOptionalChaining == 0 {
return node
}
switch node.Kind {
case ast.KindCallExpression:
return ch.visitCallExpression(node.AsCallExpression(), false)
case ast.KindPropertyAccessExpression,
ast.KindElementAccessExpression:
if node.Flags&ast.NodeFlagsOptionalChain != 0 {
return ch.visitOptionalExpression(node, false, false)
}
return ch.Visitor().VisitEachChild(node)
case ast.KindDeleteExpression:
return ch.visitDeleteExpression(node.AsDeleteExpression())
default:
return ch.Visitor().VisitEachChild(node)
}
}

func (ch *optionalChainTransformer) visitCallExpression(node *ast.CallExpression, captureThisArg bool) *ast.Node {
func (ch *syntaxTransformer) visitCallExpression(node *ast.CallExpression, captureThisArg bool) *ast.Node {
if node.Flags&ast.NodeFlagsOptionalChain != 0 {
// If `node` is an optional chain, then it is the outermost chain of an optional expression.
return ch.visitOptionalExpression(node.AsNode(), captureThisArg, false)
Expand All @@ -54,7 +30,7 @@ func (ch *optionalChainTransformer) visitCallExpression(node *ast.CallExpression
return ch.Visitor().VisitEachChild(node.AsNode())
}

func (ch *optionalChainTransformer) visitParenthesizedExpression(node *ast.ParenthesizedExpression, captureThisArg bool, isDelete bool) *ast.Node {
func (ch *syntaxTransformer) visitParenthesizedExpression(node *ast.ParenthesizedExpression, captureThisArg bool, isDelete bool) *ast.Node {
expr := ch.visitNonOptionalExpression(node.Expression, captureThisArg, isDelete)
if ast.IsSyntheticReferenceExpression(expr) {
// `(a.b)` -> { expression `((_a = a).b)`, thisArg: `_a` }
Expand All @@ -67,7 +43,7 @@ func (ch *optionalChainTransformer) visitParenthesizedExpression(node *ast.Paren
return ch.Factory().UpdateParenthesizedExpression(node, expr)
}

func (ch *optionalChainTransformer) visitPropertyOrElementAccessExpression(node *ast.Expression, captureThisArg bool, isDelete bool) *ast.Expression {
func (ch *syntaxTransformer) visitPropertyOrElementAccessExpression(node *ast.Expression, captureThisArg bool, isDelete bool) *ast.Expression {
if node.Flags&ast.NodeFlagsOptionalChain != 0 {
// If `node` is an optional chain, then it is the outermost chain of an optional expression.
return ch.visitOptionalExpression(node.AsNode(), captureThisArg, isDelete)
Expand Down Expand Up @@ -102,15 +78,15 @@ func (ch *optionalChainTransformer) visitPropertyOrElementAccessExpression(node
return expression
}

func (ch *optionalChainTransformer) visitDeleteExpression(node *ast.DeleteExpression) *ast.Node {
func (ch *syntaxTransformer) visitDeleteExpression(node *ast.DeleteExpression) *ast.Node {
unwrapped := ast.SkipParentheses(node.Expression)
if unwrapped.Flags&ast.NodeFlagsOptionalChain != 0 {
return ch.visitNonOptionalExpression(node.Expression, false, true)
}
return ch.Visitor().VisitEachChild(node.AsNode())
}

func (ch *optionalChainTransformer) visitNonOptionalExpression(node *ast.Expression, captureThisArg bool, isDelete bool) *ast.Expression {
func (ch *syntaxTransformer) visitNonOptionalExpression(node *ast.Expression, captureThisArg bool, isDelete bool) *ast.Expression {
switch node.Kind {
case ast.KindParenthesizedExpression:
return ch.visitParenthesizedExpression(node.AsParenthesizedExpression(), captureThisArg, isDelete)
Expand Down Expand Up @@ -147,7 +123,7 @@ func isCallChain(node *ast.Node) bool {
return ast.IsCallExpression(node) && node.Flags&ast.NodeFlagsOptionalChain != 0
}

func (ch *optionalChainTransformer) visitOptionalExpression(node *ast.Node, captureThisArg bool, isDelete bool) *ast.Node {
func (ch *syntaxTransformer) visitOptionalExpression(node *ast.Node, captureThisArg bool, isDelete bool) *ast.Node {
r := flattenChain(node)
expression := r.expression
chain := r.chain
Expand Down Expand Up @@ -233,8 +209,3 @@ func (ch *optionalChainTransformer) visitOptionalExpression(node *ast.Node, capt
ch.EmitContext().SetOriginal(target, node.AsNode())
return target
}

func newOptionalChainTransformer(opts *transformers.TransformOptions) *transformers.Transformer {
tx := &optionalChainTransformer{}
return tx.NewTransformer(tx.visit, opts.Context)
}
Loading
Loading