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

89 lines
3.2 KiB
Go

package inliners
import (
"strings"
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/ast"
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/core"
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/debug"
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/jsnum"
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/printer"
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/scanner"
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/transformers"
)
type ConstEnumInliningTransformer struct {
transformers.Transformer
compilerOptions *core.CompilerOptions
currentSourceFile *ast.SourceFile
emitResolver printer.EmitResolver
}
func NewConstEnumInliningTransformer(opt *transformers.TransformOptions) *transformers.Transformer {
compilerOptions := opt.CompilerOptions
emitContext := opt.Context
if compilerOptions.GetIsolatedModules() {
debug.Fail("const enums are not inlined under isolated modules")
}
tx := &ConstEnumInliningTransformer{compilerOptions: compilerOptions, emitResolver: opt.EmitResolver}
return tx.NewTransformer(tx.visit, emitContext)
}
func (tx *ConstEnumInliningTransformer) visit(node *ast.Node) *ast.Node {
switch node.Kind {
case ast.KindPropertyAccessExpression, ast.KindElementAccessExpression:
{
parse := tx.EmitContext().ParseNode(node)
if parse == nil {
return tx.Visitor().VisitEachChild(node)
}
value := tx.emitResolver.GetConstantValue(parse)
if value != nil {
var replacement *ast.Node
switch v := value.(type) {
case jsnum.Number:
if v.IsInf() {
if v.Abs() == v {
replacement = tx.Factory().NewIdentifier("Infinity")
} else {
replacement = tx.Factory().NewPrefixUnaryExpression(ast.KindMinusToken, tx.Factory().NewIdentifier("Infinity"))
}
} else if v.IsNaN() {
replacement = tx.Factory().NewIdentifier("NaN")
} else if v.Abs() == v {
replacement = tx.Factory().NewNumericLiteral(v.String())
} else {
replacement = tx.Factory().NewPrefixUnaryExpression(ast.KindMinusToken, tx.Factory().NewNumericLiteral(v.Abs().String()))
}
case string:
replacement = tx.Factory().NewStringLiteral(v)
case jsnum.PseudoBigInt: // technically not supported by strada, and issues a checker error, handled here for completeness
if v == (jsnum.PseudoBigInt{}) {
replacement = tx.Factory().NewBigIntLiteral("0")
} else if !v.Negative {
replacement = tx.Factory().NewBigIntLiteral(v.Base10Value)
} else {
replacement = tx.Factory().NewPrefixUnaryExpression(ast.KindMinusToken, tx.Factory().NewBigIntLiteral(v.Base10Value))
}
}
if tx.compilerOptions.RemoveComments.IsFalseOrUnknown() {
original := tx.EmitContext().MostOriginal(node)
if original != nil && !ast.NodeIsSynthesized(original) {
originalText := scanner.GetTextOfNode(original)
escapedText := " " + safeMultiLineComment(originalText) + " "
tx.EmitContext().AddSyntheticTrailingComment(replacement, ast.KindMultiLineCommentTrivia, escapedText, false)
}
}
return replacement
}
return tx.Visitor().VisitEachChild(node)
}
}
return tx.Visitor().VisitEachChild(node)
}
func safeMultiLineComment(text string) string {
return strings.ReplaceAll(text, "*/", "*_/")
}