2025-10-15 10:12:44 +03:00

91 lines
3.5 KiB
Go

package estransforms
import (
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/ast"
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/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 {
var target *ast.Node
var value *ast.Node
left := ch.Visitor().VisitNode(node.Left)
right := ch.Visitor().VisitNode(node.Right)
if ast.IsElementAccessExpression(left) {
// Transforms `a[x] **= b` into `(_a = a)[_x = x] = Math.pow(_a[_x], b)`
expressionTemp := ch.Factory().NewTempVariable()
ch.EmitContext().AddVariableDeclaration(expressionTemp)
argumentExpressionTemp := ch.Factory().NewTempVariable()
ch.EmitContext().AddVariableDeclaration(argumentExpressionTemp)
objExpr := ch.Factory().NewAssignmentExpression(expressionTemp, left.AsElementAccessExpression().Expression)
objExpr.Loc = left.AsElementAccessExpression().Expression.Loc
accessExpr := ch.Factory().NewAssignmentExpression(argumentExpressionTemp, left.AsElementAccessExpression().ArgumentExpression)
accessExpr.Loc = left.AsElementAccessExpression().ArgumentExpression.Loc
target = ch.Factory().NewElementAccessExpression(objExpr, nil, accessExpr, ast.NodeFlagsNone)
value = ch.Factory().NewElementAccessExpression(expressionTemp, nil, argumentExpressionTemp, ast.NodeFlagsNone)
value.Loc = left.Loc
} else if ast.IsPropertyAccessExpression(left) {
// Transforms `a.x **= b` into `(_a = a).x = Math.pow(_a.x, b)`
expressionTemp := ch.Factory().NewTempVariable()
ch.EmitContext().AddVariableDeclaration(expressionTemp)
assignment := ch.Factory().NewAssignmentExpression(expressionTemp, left.Expression())
assignment.Loc = left.Expression().Loc
target = ch.Factory().NewPropertyAccessExpression(assignment, nil, left.Name(), ast.NodeFlagsNone)
target.Loc = left.Loc
value = ch.Factory().NewPropertyAccessExpression(expressionTemp, nil, left.Name(), ast.NodeFlagsNone)
value.Loc = left.Loc
} else {
// Transforms `a **= b` into `a = Math.pow(a, b)`
target = left
value = left
}
rhs := ch.Factory().NewGlobalMethodCall("Math", "pow", []*ast.Node{value, right})
rhs.Loc = node.Loc
result := ch.Factory().NewAssignmentExpression(target, rhs)
result.Loc = node.Loc
return result
}
func (ch *exponentiationTransformer) 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)
}