type Node interface {
Type() NodeType
String() string
+ // Copy does a deep copy of the Node and all its components.
+ // To avoid type assertions, some XxxNodes also have specialized
+ // CopyXxx methods that return *XxxNode.
+ Copy() Node
}
// NodeType identifies the type of a parse tree node.
return b.String()
}
+func (l *ListNode) CopyList() *ListNode {
+ if l == nil {
+ return l
+ }
+ n := newList()
+ for _, elem := range l.Nodes {
+ n.append(elem.Copy())
+ }
+ return n
+}
+
+func (l *ListNode) Copy() Node {
+ return l.CopyList()
+}
+
// TextNode holds plain text.
type TextNode struct {
NodeType
return fmt.Sprintf("%q", t.Text)
}
+func (t *TextNode) Copy() Node {
+ return &TextNode{NodeType: NodeText, Text: append([]byte{}, t.Text...)}
+}
+
// PipeNode holds a pipeline with optional declaration
type PipeNode struct {
NodeType
return s
}
+func (p *PipeNode) CopyPipe() *PipeNode {
+ if p == nil {
+ return p
+ }
+ var decl []*VariableNode
+ for _, d := range p.Decl {
+ decl = append(decl, d.Copy().(*VariableNode))
+ }
+ n := newPipeline(p.Line, decl)
+ for _, c := range p.Cmds {
+ n.append(c.Copy().(*CommandNode))
+ }
+ return n
+}
+
+func (p *PipeNode) Copy() Node {
+ return p.CopyPipe()
+}
+
// ActionNode holds an action (something bounded by delimiters).
// Control actions have their own nodes; ActionNode represents simple
// ones such as field evaluations.
}
+func (a *ActionNode) Copy() Node {
+ return newAction(a.Line, a.Pipe.CopyPipe())
+
+}
+
// CommandNode holds a command (a pipeline inside an evaluating action).
type CommandNode struct {
NodeType
return s
}
+func (c *CommandNode) Copy() Node {
+ if c == nil {
+ return c
+ }
+ n := newCommand()
+ for _, c := range c.Args {
+ n.append(c.Copy())
+ }
+ return n
+}
+
// IdentifierNode holds an identifier.
type IdentifierNode struct {
NodeType
return i.Ident
}
+func (i *IdentifierNode) Copy() Node {
+ return NewIdentifier(i.Ident)
+}
+
// VariableNode holds a list of variable names. The dollar sign is
// part of the name.
type VariableNode struct {
return s
}
+func (v *VariableNode) Copy() Node {
+ return &VariableNode{NodeType: NodeVariable, Ident: append([]string{}, v.Ident...)}
+}
+
// DotNode holds the special identifier '.'. It is represented by a nil pointer.
type DotNode bool
return "."
}
+func (d *DotNode) Copy() Node {
+ return newDot()
+}
+
// FieldNode holds a field (identifier starting with '.').
// The names may be chained ('.x.y').
// The period is dropped from each ident.
return s
}
+func (f *FieldNode) Copy() Node {
+ return &FieldNode{NodeType: NodeField, Ident: append([]string{}, f.Ident...)}
+}
+
// BoolNode holds a boolean constant.
type BoolNode struct {
NodeType
return "false"
}
+func (b *BoolNode) Copy() Node {
+ return newBool(b.True)
+}
+
// NumberNode holds a number: signed or unsigned integer, float, or complex.
// The value is parsed and stored under all the types that can represent the value.
// This simulates in a small amount of code the behavior of Go's ideal constants.
return n.Text
}
+func (n *NumberNode) Copy() Node {
+ nn := new(NumberNode)
+ *nn = *n // Easy, fast, correct.
+ return nn
+}
+
// StringNode holds a string constant. The value has been "unquoted".
type StringNode struct {
NodeType
return s.Quoted
}
+func (s *StringNode) Copy() Node {
+ return newString(s.Quoted, s.Text)
+}
+
// endNode represents an {{end}} action. It is represented by a nil pointer.
// It does not appear in the final parse tree.
type endNode bool
return "{{end}}"
}
+func (e *endNode) Copy() Node {
+ return newEnd()
+}
+
// elseNode represents an {{else}} action. Does not appear in the final tree.
type elseNode struct {
NodeType
return "{{else}}"
}
+func (e *elseNode) Copy() Node {
+ return newElse(e.Line)
+}
+
// BranchNode is the common representation of if, range, and with.
type BranchNode struct {
NodeType
return &IfNode{BranchNode{NodeType: NodeIf, Line: line, Pipe: pipe, List: list, ElseList: elseList}}
}
+func (i *IfNode) Copy() Node {
+ return newIf(i.Line, i.Pipe.CopyPipe(), i.List.CopyList(), i.ElseList.CopyList())
+}
+
// RangeNode represents a {{range}} action and its commands.
type RangeNode struct {
BranchNode
return &RangeNode{BranchNode{NodeType: NodeRange, Line: line, Pipe: pipe, List: list, ElseList: elseList}}
}
+func (r *RangeNode) Copy() Node {
+ return newRange(r.Line, r.Pipe.CopyPipe(), r.List.CopyList(), r.ElseList.CopyList())
+}
+
// WithNode represents a {{with}} action and its commands.
type WithNode struct {
BranchNode
return &WithNode{BranchNode{NodeType: NodeWith, Line: line, Pipe: pipe, List: list, ElseList: elseList}}
}
+func (w *WithNode) Copy() Node {
+ return newWith(w.Line, w.Pipe.CopyPipe(), w.List.CopyList(), w.ElseList.CopyList())
+}
+
// TemplateNode represents a {{template}} action.
type TemplateNode struct {
NodeType
}
return fmt.Sprintf("{{template %q %s}}", t.Name, t.Pipe)
}
+
+func (t *TemplateNode) Copy() Node {
+ return newTemplate(t.Line, t.Name, t.Pipe.CopyPipe())
+}