Optimize mappings
diff --git a/ast/ast.go b/ast/ast.go
index dc7d7f3..e47a78e 100644
--- a/ast/ast.go
+++ b/ast/ast.go
@@ -29,6 +29,7 @@
// Node represents a node in the AST
type Node interface {
Type() NodeType
+ Clone() Node
}
// Rewrite represents a koral:rewrite
@@ -88,6 +89,18 @@
return RewriteNode
}
+// Clone creates a deep copy of the Rewrite node
+func (r *Rewrite) Clone() Node {
+ return &Rewrite{
+ Editor: r.Editor,
+ Operation: r.Operation,
+ Scope: r.Scope,
+ Src: r.Src,
+ Comment: r.Comment,
+ Original: r.Original, // Note: this is a shallow copy of the Original field
+ }
+}
+
// MarshalJSON implements custom JSON marshaling to ensure clean output
func (r *Rewrite) MarshalJSON() ([]byte, error) {
// Create a map with only the modern field names
@@ -128,6 +141,27 @@
return TokenNode
}
+// Clone creates a deep copy of the Token node
+func (t *Token) Clone() Node {
+ var clonedWrap Node
+ if t.Wrap != nil {
+ clonedWrap = t.Wrap.Clone()
+ }
+ tc := &Token{
+ Wrap: clonedWrap,
+ }
+
+ if t.Rewrites != nil {
+ clonedRewrites := make([]Rewrite, len(t.Rewrites))
+ for i, rewrite := range t.Rewrites {
+ clonedRewrites[i] = *rewrite.Clone().(*Rewrite)
+ }
+ tc.Rewrites = clonedRewrites
+ }
+
+ return tc
+}
+
// TermGroup represents a koral:termGroup
type TermGroup struct {
Operands []Node `json:"operands"`
@@ -139,6 +173,27 @@
return TermGroupNode
}
+// Clone creates a deep copy of the TermGroup node
+func (tg *TermGroup) Clone() Node {
+ clonedOperands := make([]Node, len(tg.Operands))
+ for i, operand := range tg.Operands {
+ clonedOperands[i] = operand.Clone()
+ }
+ tgc := &TermGroup{
+ Operands: clonedOperands,
+ Relation: tg.Relation,
+ }
+ if tg.Rewrites != nil {
+ clonedRewrites := make([]Rewrite, len(tg.Rewrites))
+ for i, rewrite := range tg.Rewrites {
+ clonedRewrites[i] = *rewrite.Clone().(*Rewrite)
+ }
+ tgc.Rewrites = clonedRewrites
+ }
+
+ return tgc
+}
+
// Term represents a koral:term
type Term struct {
Foundry string `json:"foundry"`
@@ -153,6 +208,27 @@
return TermNode
}
+// Clone creates a deep copy of the Term node
+func (t *Term) Clone() Node {
+
+ tc := &Term{
+ Foundry: t.Foundry,
+ Key: t.Key,
+ Layer: t.Layer,
+ Match: t.Match,
+ Value: t.Value,
+ }
+
+ if t.Rewrites != nil {
+ clonedRewrites := make([]Rewrite, len(t.Rewrites))
+ for i, rewrite := range t.Rewrites {
+ clonedRewrites[i] = *rewrite.Clone().(*Rewrite)
+ }
+ tc.Rewrites = clonedRewrites
+ }
+ return tc
+}
+
// Pattern represents a pattern to match in the AST
type Pattern struct {
Root Node
@@ -174,3 +250,61 @@
func (c *CatchallNode) Type() NodeType {
return NodeType(c.NodeType)
}
+
+// Clone creates a deep copy of the CatchallNode
+func (c *CatchallNode) Clone() Node {
+ newNode := &CatchallNode{
+ NodeType: c.NodeType,
+ }
+
+ // Handle RawContent properly - preserve nil if it's nil
+ if c.RawContent != nil {
+ newNode.RawContent = make(json.RawMessage, len(c.RawContent))
+ copy(newNode.RawContent, c.RawContent)
+ }
+
+ if c.Wrap != nil {
+ newNode.Wrap = c.Wrap.Clone()
+ }
+
+ if len(c.Operands) > 0 {
+ newNode.Operands = make([]Node, len(c.Operands))
+ for i, operand := range c.Operands {
+ newNode.Operands[i] = operand.Clone()
+ }
+ }
+
+ return newNode
+}
+
+// ApplyFoundryAndLayerOverrides recursively applies foundry and layer overrides to terms
+func ApplyFoundryAndLayerOverrides(node Node, foundry, layer string) {
+ if node == nil {
+ return
+ }
+
+ switch n := node.(type) {
+ case *Term:
+ if foundry != "" {
+ n.Foundry = foundry
+ }
+ if layer != "" {
+ n.Layer = layer
+ }
+ case *TermGroup:
+ for _, op := range n.Operands {
+ ApplyFoundryAndLayerOverrides(op, foundry, layer)
+ }
+ case *Token:
+ if n.Wrap != nil {
+ ApplyFoundryAndLayerOverrides(n.Wrap, foundry, layer)
+ }
+ case *CatchallNode:
+ if n.Wrap != nil {
+ ApplyFoundryAndLayerOverrides(n.Wrap, foundry, layer)
+ }
+ for _, op := range n.Operands {
+ ApplyFoundryAndLayerOverrides(op, foundry, layer)
+ }
+ }
+}