2025-11-08 09:37:30 +03:00

87 lines
2.6 KiB
Go

package ast
import "efprojects.com/kitten-ipc/kitcom/internal/tsgo/core"
// Ideally, this would get cached on the node factory so there's only ever one set of closures made per factory
func getDeepCloneVisitor(f *NodeFactory, syntheticLocation bool) *NodeVisitor {
var visitor *NodeVisitor
visitor = NewNodeVisitor(
func(node *Node) *Node {
visited := visitor.VisitEachChild(node)
if visited != node {
if syntheticLocation {
visited.Loc = core.NewTextRange(-1, -1)
}
return visited
}
c := node.Clone(f) // forcibly clone leaf nodes, which will then cascade new nodes/arrays upwards via `update` calls
// In strada, `factory.cloneNode` was dynamic and did _not_ clone positions for any "special cases", meanwhile
// Node.Clone in corsa reliably uses `Update` calls for all nodes and so copies locations by default.
// Deep clones are done to copy a node across files, so here, we explicitly make the location range synthetic on all cloned nodes
if syntheticLocation {
c.Loc = core.NewTextRange(-1, -1)
}
return c
},
f,
NodeVisitorHooks{
VisitNodes: func(nodes *NodeList, v *NodeVisitor) *NodeList {
if nodes == nil {
return nil
}
visited := v.VisitNodes(nodes)
var newList *NodeList
if visited != nodes {
newList = visited
} else {
newList = nodes.Clone(v.Factory)
}
if syntheticLocation {
newList.Loc = core.NewTextRange(-1, -1)
if nodes.HasTrailingComma() {
newList.Nodes[len(newList.Nodes)-1].Loc = core.NewTextRange(-2, -2)
}
}
return newList
},
VisitModifiers: func(nodes *ModifierList, v *NodeVisitor) *ModifierList {
if nodes == nil {
return nil
}
visited := v.VisitModifiers(nodes)
var newList *ModifierList
if visited != nodes {
newList = visited
} else {
newList = nodes.Clone(v.Factory)
}
if syntheticLocation {
newList.Loc = core.NewTextRange(-1, -1)
if nodes.HasTrailingComma() {
newList.Nodes[len(newList.Nodes)-1].Loc = core.NewTextRange(-2, -2)
}
}
return newList
},
},
)
return visitor
}
func (f *NodeFactory) DeepCloneNode(node *Node) *Node {
return getDeepCloneVisitor(f, true /*syntheticLocation*/).VisitNode(node)
}
func (f *NodeFactory) DeepCloneReparse(node *Node) *Node {
if node != nil {
node = getDeepCloneVisitor(f, false /*syntheticLocation*/).VisitNode(node)
SetParentInChildren(node)
node.Flags |= NodeFlagsReparsed
}
return node
}
func (f *NodeFactory) DeepCloneReparseModifiers(modifiers *ModifierList) *ModifierList {
return getDeepCloneVisitor(f, false /*syntheticLocation*/).VisitModifiers(modifiers)
}