87 lines
2.6 KiB
Go
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)
|
|
}
|