node.go (24824B)
1 // Copyright 2011 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4
5 // Parse nodes.
6
7 package parse
8
9 import (
10 "fmt"
11 "strconv"
12 "strings"
13 )
14
15 var textFormat = "%s" // Changed to "%q" in tests for better error messages.
16
17 // A Node is an element in the parse tree. The interface is trivial.
18 // The interface contains an unexported method so that only
19 // types local to this package can satisfy it.
20 type Node interface {
21 Type() NodeType
22 String() string
23 // Copy does a deep copy of the Node and all its components.
24 // To avoid type assertions, some XxxNodes also have specialized
25 // CopyXxx methods that return *XxxNode.
26 Copy() Node
27 Position() Pos // byte position of start of node in full original input string
28 // tree returns the containing *Tree.
29 // It is unexported so all implementations of Node are in this package.
30 tree() *Tree
31 // writeTo writes the String output to the builder.
32 writeTo(*strings.Builder)
33 }
34
35 // NodeType identifies the type of a parse tree node.
36 type NodeType int
37
38 // Pos represents a byte position in the original input text from which
39 // this template was parsed.
40 type Pos int
41
42 func (p Pos) Position() Pos {
43 return p
44 }
45
46 // Type returns itself and provides an easy default implementation
47 // for embedding in a Node. Embedded in all non-trivial Nodes.
48 func (t NodeType) Type() NodeType {
49 return t
50 }
51
52 const (
53 NodeText NodeType = iota // Plain text.
54 NodeAction // A non-control action such as a field evaluation.
55 NodeBool // A boolean constant.
56 NodeChain // A sequence of field accesses.
57 NodeCommand // An element of a pipeline.
58 NodeDot // The cursor, dot.
59 nodeElse // An else action. Not added to tree.
60 nodeEnd // An end action. Not added to tree.
61 NodeField // A field or method name.
62 NodeIdentifier // An identifier; always a function name.
63 NodeIf // An if action.
64 NodeList // A list of Nodes.
65 NodeNil // An untyped nil constant.
66 NodeNumber // A numerical constant.
67 NodePipe // A pipeline of commands.
68 NodeRange // A range action.
69 NodeString // A string constant.
70 NodeTemplate // A template invocation action.
71 NodeVariable // A $ variable.
72 NodeWith // A with action.
73 NodeComment // A comment.
74 NodeBreak // A break action.
75 NodeContinue // A continue action.
76 )
77
78 // Nodes.
79
80 // ListNode holds a sequence of nodes.
81 type ListNode struct {
82 NodeType
83 Pos
84 tr *Tree
85 Nodes []Node // The element nodes in lexical order.
86 }
87
88 func (t *Tree) newList(pos Pos) *ListNode {
89 return &ListNode{tr: t, NodeType: NodeList, Pos: pos}
90 }
91
92 func (l *ListNode) append(n Node) {
93 l.Nodes = append(l.Nodes, n)
94 }
95
96 func (l *ListNode) tree() *Tree {
97 return l.tr
98 }
99
100 func (l *ListNode) String() string {
101 var sb strings.Builder
102 l.writeTo(&sb)
103 return sb.String()
104 }
105
106 func (l *ListNode) writeTo(sb *strings.Builder) {
107 for _, n := range l.Nodes {
108 n.writeTo(sb)
109 }
110 }
111
112 func (l *ListNode) CopyList() *ListNode {
113 if l == nil {
114 return l
115 }
116 n := l.tr.newList(l.Pos)
117 for _, elem := range l.Nodes {
118 n.append(elem.Copy())
119 }
120 return n
121 }
122
123 func (l *ListNode) Copy() Node {
124 return l.CopyList()
125 }
126
127 // TextNode holds plain text.
128 type TextNode struct {
129 NodeType
130 Pos
131 tr *Tree
132 Text []byte // The text; may span newlines.
133 }
134
135 func (t *Tree) newText(pos Pos, text string) *TextNode {
136 return &TextNode{tr: t, NodeType: NodeText, Pos: pos, Text: []byte(text)}
137 }
138
139 func (t *TextNode) String() string {
140 return fmt.Sprintf(textFormat, t.Text)
141 }
142
143 func (t *TextNode) writeTo(sb *strings.Builder) {
144 sb.WriteString(t.String())
145 }
146
147 func (t *TextNode) tree() *Tree {
148 return t.tr
149 }
150
151 func (t *TextNode) Copy() Node {
152 return &TextNode{tr: t.tr, NodeType: NodeText, Pos: t.Pos, Text: append([]byte{}, t.Text...)}
153 }
154
155 // CommentNode holds a comment.
156 type CommentNode struct {
157 NodeType
158 Pos
159 tr *Tree
160 Text string // Comment text.
161 }
162
163 func (t *Tree) newComment(pos Pos, text string) *CommentNode {
164 return &CommentNode{tr: t, NodeType: NodeComment, Pos: pos, Text: text}
165 }
166
167 func (c *CommentNode) String() string {
168 var sb strings.Builder
169 c.writeTo(&sb)
170 return sb.String()
171 }
172
173 func (c *CommentNode) writeTo(sb *strings.Builder) {
174 sb.WriteString("{{")
175 sb.WriteString(c.Text)
176 sb.WriteString("}}")
177 }
178
179 func (c *CommentNode) tree() *Tree {
180 return c.tr
181 }
182
183 func (c *CommentNode) Copy() Node {
184 return &CommentNode{tr: c.tr, NodeType: NodeComment, Pos: c.Pos, Text: c.Text}
185 }
186
187 // PipeNode holds a pipeline with optional declaration
188 type PipeNode struct {
189 NodeType
190 Pos
191 tr *Tree
192 Line int // The line number in the input. Deprecated: Kept for compatibility.
193 IsAssign bool // The variables are being assigned, not declared.
194 Decl []*VariableNode // Variables in lexical order.
195 Cmds []*CommandNode // The commands in lexical order.
196 }
197
198 func (t *Tree) newPipeline(pos Pos, line int, vars []*VariableNode) *PipeNode {
199 return &PipeNode{tr: t, NodeType: NodePipe, Pos: pos, Line: line, Decl: vars}
200 }
201
202 func (p *PipeNode) append(command *CommandNode) {
203 p.Cmds = append(p.Cmds, command)
204 }
205
206 func (p *PipeNode) String() string {
207 var sb strings.Builder
208 p.writeTo(&sb)
209 return sb.String()
210 }
211
212 func (p *PipeNode) writeTo(sb *strings.Builder) {
213 if len(p.Decl) > 0 {
214 for i, v := range p.Decl {
215 if i > 0 {
216 sb.WriteString(", ")
217 }
218 v.writeTo(sb)
219 }
220 sb.WriteString(" := ")
221 }
222 for i, c := range p.Cmds {
223 if i > 0 {
224 sb.WriteString(" | ")
225 }
226 c.writeTo(sb)
227 }
228 }
229
230 func (p *PipeNode) tree() *Tree {
231 return p.tr
232 }
233
234 func (p *PipeNode) CopyPipe() *PipeNode {
235 if p == nil {
236 return p
237 }
238 vars := make([]*VariableNode, len(p.Decl))
239 for i, d := range p.Decl {
240 vars[i] = d.Copy().(*VariableNode)
241 }
242 n := p.tr.newPipeline(p.Pos, p.Line, vars)
243 n.IsAssign = p.IsAssign
244 for _, c := range p.Cmds {
245 n.append(c.Copy().(*CommandNode))
246 }
247 return n
248 }
249
250 func (p *PipeNode) Copy() Node {
251 return p.CopyPipe()
252 }
253
254 // ActionNode holds an action (something bounded by delimiters).
255 // Control actions have their own nodes; ActionNode represents simple
256 // ones such as field evaluations and parenthesized pipelines.
257 type ActionNode struct {
258 NodeType
259 Pos
260 tr *Tree
261 Line int // The line number in the input. Deprecated: Kept for compatibility.
262 Pipe *PipeNode // The pipeline in the action.
263 }
264
265 func (t *Tree) newAction(pos Pos, line int, pipe *PipeNode) *ActionNode {
266 return &ActionNode{tr: t, NodeType: NodeAction, Pos: pos, Line: line, Pipe: pipe}
267 }
268
269 func (a *ActionNode) String() string {
270 var sb strings.Builder
271 a.writeTo(&sb)
272 return sb.String()
273 }
274
275 func (a *ActionNode) writeTo(sb *strings.Builder) {
276 sb.WriteString("{{")
277 a.Pipe.writeTo(sb)
278 sb.WriteString("}}")
279 }
280
281 func (a *ActionNode) tree() *Tree {
282 return a.tr
283 }
284
285 func (a *ActionNode) Copy() Node {
286 return a.tr.newAction(a.Pos, a.Line, a.Pipe.CopyPipe())
287
288 }
289
290 // CommandNode holds a command (a pipeline inside an evaluating action).
291 type CommandNode struct {
292 NodeType
293 Pos
294 tr *Tree
295 Args []Node // Arguments in lexical order: Identifier, field, or constant.
296 }
297
298 func (t *Tree) newCommand(pos Pos) *CommandNode {
299 return &CommandNode{tr: t, NodeType: NodeCommand, Pos: pos}
300 }
301
302 func (c *CommandNode) append(arg Node) {
303 c.Args = append(c.Args, arg)
304 }
305
306 func (c *CommandNode) String() string {
307 var sb strings.Builder
308 c.writeTo(&sb)
309 return sb.String()
310 }
311
312 func (c *CommandNode) writeTo(sb *strings.Builder) {
313 for i, arg := range c.Args {
314 if i > 0 {
315 sb.WriteByte(' ')
316 }
317 if arg, ok := arg.(*PipeNode); ok {
318 sb.WriteByte('(')
319 arg.writeTo(sb)
320 sb.WriteByte(')')
321 continue
322 }
323 arg.writeTo(sb)
324 }
325 }
326
327 func (c *CommandNode) tree() *Tree {
328 return c.tr
329 }
330
331 func (c *CommandNode) Copy() Node {
332 if c == nil {
333 return c
334 }
335 n := c.tr.newCommand(c.Pos)
336 for _, c := range c.Args {
337 n.append(c.Copy())
338 }
339 return n
340 }
341
342 // IdentifierNode holds an identifier.
343 type IdentifierNode struct {
344 NodeType
345 Pos
346 tr *Tree
347 Ident string // The identifier's name.
348 }
349
350 // NewIdentifier returns a new IdentifierNode with the given identifier name.
351 func NewIdentifier(ident string) *IdentifierNode {
352 return &IdentifierNode{NodeType: NodeIdentifier, Ident: ident}
353 }
354
355 // SetPos sets the position. NewIdentifier is a public method so we can't modify its signature.
356 // Chained for convenience.
357 // TODO: fix one day?
358 func (i *IdentifierNode) SetPos(pos Pos) *IdentifierNode {
359 i.Pos = pos
360 return i
361 }
362
363 // SetTree sets the parent tree for the node. NewIdentifier is a public method so we can't modify its signature.
364 // Chained for convenience.
365 // TODO: fix one day?
366 func (i *IdentifierNode) SetTree(t *Tree) *IdentifierNode {
367 i.tr = t
368 return i
369 }
370
371 func (i *IdentifierNode) String() string {
372 return i.Ident
373 }
374
375 func (i *IdentifierNode) writeTo(sb *strings.Builder) {
376 sb.WriteString(i.String())
377 }
378
379 func (i *IdentifierNode) tree() *Tree {
380 return i.tr
381 }
382
383 func (i *IdentifierNode) Copy() Node {
384 return NewIdentifier(i.Ident).SetTree(i.tr).SetPos(i.Pos)
385 }
386
387 // VariableNode holds a list of variable names, possibly with chained field
388 // accesses. The dollar sign is part of the (first) name.
389 type VariableNode struct {
390 NodeType
391 Pos
392 tr *Tree
393 Ident []string // Variable name and fields in lexical order.
394 }
395
396 func (t *Tree) newVariable(pos Pos, ident string) *VariableNode {
397 return &VariableNode{tr: t, NodeType: NodeVariable, Pos: pos, Ident: strings.Split(ident, ".")}
398 }
399
400 func (v *VariableNode) String() string {
401 var sb strings.Builder
402 v.writeTo(&sb)
403 return sb.String()
404 }
405
406 func (v *VariableNode) writeTo(sb *strings.Builder) {
407 for i, id := range v.Ident {
408 if i > 0 {
409 sb.WriteByte('.')
410 }
411 sb.WriteString(id)
412 }
413 }
414
415 func (v *VariableNode) tree() *Tree {
416 return v.tr
417 }
418
419 func (v *VariableNode) Copy() Node {
420 return &VariableNode{tr: v.tr, NodeType: NodeVariable, Pos: v.Pos, Ident: append([]string{}, v.Ident...)}
421 }
422
423 // DotNode holds the special identifier '.'.
424 type DotNode struct {
425 NodeType
426 Pos
427 tr *Tree
428 }
429
430 func (t *Tree) newDot(pos Pos) *DotNode {
431 return &DotNode{tr: t, NodeType: NodeDot, Pos: pos}
432 }
433
434 func (d *DotNode) Type() NodeType {
435 // Override method on embedded NodeType for API compatibility.
436 // TODO: Not really a problem; could change API without effect but
437 // api tool complains.
438 return NodeDot
439 }
440
441 func (d *DotNode) String() string {
442 return "."
443 }
444
445 func (d *DotNode) writeTo(sb *strings.Builder) {
446 sb.WriteString(d.String())
447 }
448
449 func (d *DotNode) tree() *Tree {
450 return d.tr
451 }
452
453 func (d *DotNode) Copy() Node {
454 return d.tr.newDot(d.Pos)
455 }
456
457 // NilNode holds the special identifier 'nil' representing an untyped nil constant.
458 type NilNode struct {
459 NodeType
460 Pos
461 tr *Tree
462 }
463
464 func (t *Tree) newNil(pos Pos) *NilNode {
465 return &NilNode{tr: t, NodeType: NodeNil, Pos: pos}
466 }
467
468 func (n *NilNode) Type() NodeType {
469 // Override method on embedded NodeType for API compatibility.
470 // TODO: Not really a problem; could change API without effect but
471 // api tool complains.
472 return NodeNil
473 }
474
475 func (n *NilNode) String() string {
476 return "nil"
477 }
478
479 func (n *NilNode) writeTo(sb *strings.Builder) {
480 sb.WriteString(n.String())
481 }
482
483 func (n *NilNode) tree() *Tree {
484 return n.tr
485 }
486
487 func (n *NilNode) Copy() Node {
488 return n.tr.newNil(n.Pos)
489 }
490
491 // FieldNode holds a field (identifier starting with '.').
492 // The names may be chained ('.x.y').
493 // The period is dropped from each ident.
494 type FieldNode struct {
495 NodeType
496 Pos
497 tr *Tree
498 Ident []string // The identifiers in lexical order.
499 }
500
501 func (t *Tree) newField(pos Pos, ident string) *FieldNode {
502 return &FieldNode{tr: t, NodeType: NodeField, Pos: pos, Ident: strings.Split(ident[1:], ".")} // [1:] to drop leading period
503 }
504
505 func (f *FieldNode) String() string {
506 var sb strings.Builder
507 f.writeTo(&sb)
508 return sb.String()
509 }
510
511 func (f *FieldNode) writeTo(sb *strings.Builder) {
512 for _, id := range f.Ident {
513 sb.WriteByte('.')
514 sb.WriteString(id)
515 }
516 }
517
518 func (f *FieldNode) tree() *Tree {
519 return f.tr
520 }
521
522 func (f *FieldNode) Copy() Node {
523 return &FieldNode{tr: f.tr, NodeType: NodeField, Pos: f.Pos, Ident: append([]string{}, f.Ident...)}
524 }
525
526 // ChainNode holds a term followed by a chain of field accesses (identifier starting with '.').
527 // The names may be chained ('.x.y').
528 // The periods are dropped from each ident.
529 type ChainNode struct {
530 NodeType
531 Pos
532 tr *Tree
533 Node Node
534 Field []string // The identifiers in lexical order.
535 }
536
537 func (t *Tree) newChain(pos Pos, node Node) *ChainNode {
538 return &ChainNode{tr: t, NodeType: NodeChain, Pos: pos, Node: node}
539 }
540
541 // Add adds the named field (which should start with a period) to the end of the chain.
542 func (c *ChainNode) Add(field string) {
543 if len(field) == 0 || field[0] != '.' {
544 panic("no dot in field")
545 }
546 field = field[1:] // Remove leading dot.
547 if field == "" {
548 panic("empty field")
549 }
550 c.Field = append(c.Field, field)
551 }
552
553 func (c *ChainNode) String() string {
554 var sb strings.Builder
555 c.writeTo(&sb)
556 return sb.String()
557 }
558
559 func (c *ChainNode) writeTo(sb *strings.Builder) {
560 if _, ok := c.Node.(*PipeNode); ok {
561 sb.WriteByte('(')
562 c.Node.writeTo(sb)
563 sb.WriteByte(')')
564 } else {
565 c.Node.writeTo(sb)
566 }
567 for _, field := range c.Field {
568 sb.WriteByte('.')
569 sb.WriteString(field)
570 }
571 }
572
573 func (c *ChainNode) tree() *Tree {
574 return c.tr
575 }
576
577 func (c *ChainNode) Copy() Node {
578 return &ChainNode{tr: c.tr, NodeType: NodeChain, Pos: c.Pos, Node: c.Node, Field: append([]string{}, c.Field...)}
579 }
580
581 // BoolNode holds a boolean constant.
582 type BoolNode struct {
583 NodeType
584 Pos
585 tr *Tree
586 True bool // The value of the boolean constant.
587 }
588
589 func (t *Tree) newBool(pos Pos, true bool) *BoolNode {
590 return &BoolNode{tr: t, NodeType: NodeBool, Pos: pos, True: true}
591 }
592
593 func (b *BoolNode) String() string {
594 if b.True {
595 return "true"
596 }
597 return "false"
598 }
599
600 func (b *BoolNode) writeTo(sb *strings.Builder) {
601 sb.WriteString(b.String())
602 }
603
604 func (b *BoolNode) tree() *Tree {
605 return b.tr
606 }
607
608 func (b *BoolNode) Copy() Node {
609 return b.tr.newBool(b.Pos, b.True)
610 }
611
612 // NumberNode holds a number: signed or unsigned integer, float, or complex.
613 // The value is parsed and stored under all the types that can represent the value.
614 // This simulates in a small amount of code the behavior of Go's ideal constants.
615 type NumberNode struct {
616 NodeType
617 Pos
618 tr *Tree
619 IsInt bool // Number has an integral value.
620 IsUint bool // Number has an unsigned integral value.
621 IsFloat bool // Number has a floating-point value.
622 IsComplex bool // Number is complex.
623 Int64 int64 // The signed integer value.
624 Uint64 uint64 // The unsigned integer value.
625 Float64 float64 // The floating-point value.
626 Complex128 complex128 // The complex value.
627 Text string // The original textual representation from the input.
628 }
629
630 func (t *Tree) newNumber(pos Pos, text string, typ itemType) (*NumberNode, error) {
631 n := &NumberNode{tr: t, NodeType: NodeNumber, Pos: pos, Text: text}
632 switch typ {
633 case itemCharConstant:
634 rune, _, tail, err := strconv.UnquoteChar(text[1:], text[0])
635 if err != nil {
636 return nil, err
637 }
638 if tail != "'" {
639 return nil, fmt.Errorf("malformed character constant: %s", text)
640 }
641 n.Int64 = int64(rune)
642 n.IsInt = true
643 n.Uint64 = uint64(rune)
644 n.IsUint = true
645 n.Float64 = float64(rune) // odd but those are the rules.
646 n.IsFloat = true
647 return n, nil
648 case itemComplex:
649 // fmt.Sscan can parse the pair, so let it do the work.
650 if _, err := fmt.Sscan(text, &n.Complex128); err != nil {
651 return nil, err
652 }
653 n.IsComplex = true
654 n.simplifyComplex()
655 return n, nil
656 }
657 // Imaginary constants can only be complex unless they are zero.
658 if len(text) > 0 && text[len(text)-1] == 'i' {
659 f, err := strconv.ParseFloat(text[:len(text)-1], 64)
660 if err == nil {
661 n.IsComplex = true
662 n.Complex128 = complex(0, f)
663 n.simplifyComplex()
664 return n, nil
665 }
666 }
667 // Do integer test first so we get 0x123 etc.
668 u, err := strconv.ParseUint(text, 0, 64) // will fail for -0; fixed below.
669 if err == nil {
670 n.IsUint = true
671 n.Uint64 = u
672 }
673 i, err := strconv.ParseInt(text, 0, 64)
674 if err == nil {
675 n.IsInt = true
676 n.Int64 = i
677 if i == 0 {
678 n.IsUint = true // in case of -0.
679 n.Uint64 = u
680 }
681 }
682 // If an integer extraction succeeded, promote the float.
683 if n.IsInt {
684 n.IsFloat = true
685 n.Float64 = float64(n.Int64)
686 } else if n.IsUint {
687 n.IsFloat = true
688 n.Float64 = float64(n.Uint64)
689 } else {
690 f, err := strconv.ParseFloat(text, 64)
691 if err == nil {
692 // If we parsed it as a float but it looks like an integer,
693 // it's a huge number too large to fit in an int. Reject it.
694 if !strings.ContainsAny(text, ".eEpP") {
695 return nil, fmt.Errorf("integer overflow: %q", text)
696 }
697 n.IsFloat = true
698 n.Float64 = f
699 // If a floating-point extraction succeeded, extract the int if needed.
700 if !n.IsInt && float64(int64(f)) == f {
701 n.IsInt = true
702 n.Int64 = int64(f)
703 }
704 if !n.IsUint && float64(uint64(f)) == f {
705 n.IsUint = true
706 n.Uint64 = uint64(f)
707 }
708 }
709 }
710 if !n.IsInt && !n.IsUint && !n.IsFloat {
711 return nil, fmt.Errorf("illegal number syntax: %q", text)
712 }
713 return n, nil
714 }
715
716 // simplifyComplex pulls out any other types that are represented by the complex number.
717 // These all require that the imaginary part be zero.
718 func (n *NumberNode) simplifyComplex() {
719 n.IsFloat = imag(n.Complex128) == 0
720 if n.IsFloat {
721 n.Float64 = real(n.Complex128)
722 n.IsInt = float64(int64(n.Float64)) == n.Float64
723 if n.IsInt {
724 n.Int64 = int64(n.Float64)
725 }
726 n.IsUint = float64(uint64(n.Float64)) == n.Float64
727 if n.IsUint {
728 n.Uint64 = uint64(n.Float64)
729 }
730 }
731 }
732
733 func (n *NumberNode) String() string {
734 return n.Text
735 }
736
737 func (n *NumberNode) writeTo(sb *strings.Builder) {
738 sb.WriteString(n.String())
739 }
740
741 func (n *NumberNode) tree() *Tree {
742 return n.tr
743 }
744
745 func (n *NumberNode) Copy() Node {
746 nn := new(NumberNode)
747 *nn = *n // Easy, fast, correct.
748 return nn
749 }
750
751 // StringNode holds a string constant. The value has been "unquoted".
752 type StringNode struct {
753 NodeType
754 Pos
755 tr *Tree
756 Quoted string // The original text of the string, with quotes.
757 Text string // The string, after quote processing.
758 }
759
760 func (t *Tree) newString(pos Pos, orig, text string) *StringNode {
761 return &StringNode{tr: t, NodeType: NodeString, Pos: pos, Quoted: orig, Text: text}
762 }
763
764 func (s *StringNode) String() string {
765 return s.Quoted
766 }
767
768 func (s *StringNode) writeTo(sb *strings.Builder) {
769 sb.WriteString(s.String())
770 }
771
772 func (s *StringNode) tree() *Tree {
773 return s.tr
774 }
775
776 func (s *StringNode) Copy() Node {
777 return s.tr.newString(s.Pos, s.Quoted, s.Text)
778 }
779
780 // endNode represents an {{end}} action.
781 // It does not appear in the final parse tree.
782 type endNode struct {
783 NodeType
784 Pos
785 tr *Tree
786 }
787
788 func (t *Tree) newEnd(pos Pos) *endNode {
789 return &endNode{tr: t, NodeType: nodeEnd, Pos: pos}
790 }
791
792 func (e *endNode) String() string {
793 return "{{end}}"
794 }
795
796 func (e *endNode) writeTo(sb *strings.Builder) {
797 sb.WriteString(e.String())
798 }
799
800 func (e *endNode) tree() *Tree {
801 return e.tr
802 }
803
804 func (e *endNode) Copy() Node {
805 return e.tr.newEnd(e.Pos)
806 }
807
808 // elseNode represents an {{else}} action. Does not appear in the final tree.
809 type elseNode struct {
810 NodeType
811 Pos
812 tr *Tree
813 Line int // The line number in the input. Deprecated: Kept for compatibility.
814 }
815
816 func (t *Tree) newElse(pos Pos, line int) *elseNode {
817 return &elseNode{tr: t, NodeType: nodeElse, Pos: pos, Line: line}
818 }
819
820 func (e *elseNode) Type() NodeType {
821 return nodeElse
822 }
823
824 func (e *elseNode) String() string {
825 return "{{else}}"
826 }
827
828 func (e *elseNode) writeTo(sb *strings.Builder) {
829 sb.WriteString(e.String())
830 }
831
832 func (e *elseNode) tree() *Tree {
833 return e.tr
834 }
835
836 func (e *elseNode) Copy() Node {
837 return e.tr.newElse(e.Pos, e.Line)
838 }
839
840 // BranchNode is the common representation of if, range, and with.
841 type BranchNode struct {
842 NodeType
843 Pos
844 tr *Tree
845 Line int // The line number in the input. Deprecated: Kept for compatibility.
846 Pipe *PipeNode // The pipeline to be evaluated.
847 List *ListNode // What to execute if the value is non-empty.
848 ElseList *ListNode // What to execute if the value is empty (nil if absent).
849 }
850
851 func (b *BranchNode) String() string {
852 var sb strings.Builder
853 b.writeTo(&sb)
854 return sb.String()
855 }
856
857 func (b *BranchNode) writeTo(sb *strings.Builder) {
858 name := ""
859 switch b.NodeType {
860 case NodeIf:
861 name = "if"
862 case NodeRange:
863 name = "range"
864 case NodeWith:
865 name = "with"
866 default:
867 panic("unknown branch type")
868 }
869 sb.WriteString("{{")
870 sb.WriteString(name)
871 sb.WriteByte(' ')
872 b.Pipe.writeTo(sb)
873 sb.WriteString("}}")
874 b.List.writeTo(sb)
875 if b.ElseList != nil {
876 sb.WriteString("{{else}}")
877 b.ElseList.writeTo(sb)
878 }
879 sb.WriteString("{{end}}")
880 }
881
882 func (b *BranchNode) tree() *Tree {
883 return b.tr
884 }
885
886 func (b *BranchNode) Copy() Node {
887 switch b.NodeType {
888 case NodeIf:
889 return b.tr.newIf(b.Pos, b.Line, b.Pipe, b.List, b.ElseList)
890 case NodeRange:
891 return b.tr.newRange(b.Pos, b.Line, b.Pipe, b.List, b.ElseList)
892 case NodeWith:
893 return b.tr.newWith(b.Pos, b.Line, b.Pipe, b.List, b.ElseList)
894 default:
895 panic("unknown branch type")
896 }
897 }
898
899 // IfNode represents an {{if}} action and its commands.
900 type IfNode struct {
901 BranchNode
902 }
903
904 func (t *Tree) newIf(pos Pos, line int, pipe *PipeNode, list, elseList *ListNode) *IfNode {
905 return &IfNode{BranchNode{tr: t, NodeType: NodeIf, Pos: pos, Line: line, Pipe: pipe, List: list, ElseList: elseList}}
906 }
907
908 func (i *IfNode) Copy() Node {
909 return i.tr.newIf(i.Pos, i.Line, i.Pipe.CopyPipe(), i.List.CopyList(), i.ElseList.CopyList())
910 }
911
912 // BreakNode represents a {{break}} action.
913 type BreakNode struct {
914 tr *Tree
915 NodeType
916 Pos
917 Line int
918 }
919
920 func (t *Tree) newBreak(pos Pos, line int) *BreakNode {
921 return &BreakNode{tr: t, NodeType: NodeBreak, Pos: pos, Line: line}
922 }
923
924 func (b *BreakNode) Copy() Node { return b.tr.newBreak(b.Pos, b.Line) }
925 func (b *BreakNode) String() string { return "{{break}}" }
926 func (b *BreakNode) tree() *Tree { return b.tr }
927 func (b *BreakNode) writeTo(sb *strings.Builder) { sb.WriteString("{{break}}") }
928
929 // ContinueNode represents a {{continue}} action.
930 type ContinueNode struct {
931 tr *Tree
932 NodeType
933 Pos
934 Line int
935 }
936
937 func (t *Tree) newContinue(pos Pos, line int) *ContinueNode {
938 return &ContinueNode{tr: t, NodeType: NodeContinue, Pos: pos, Line: line}
939 }
940
941 func (c *ContinueNode) Copy() Node { return c.tr.newContinue(c.Pos, c.Line) }
942 func (c *ContinueNode) String() string { return "{{continue}}" }
943 func (c *ContinueNode) tree() *Tree { return c.tr }
944 func (c *ContinueNode) writeTo(sb *strings.Builder) { sb.WriteString("{{continue}}") }
945
946 // RangeNode represents a {{range}} action and its commands.
947 type RangeNode struct {
948 BranchNode
949 }
950
951 func (t *Tree) newRange(pos Pos, line int, pipe *PipeNode, list, elseList *ListNode) *RangeNode {
952 return &RangeNode{BranchNode{tr: t, NodeType: NodeRange, Pos: pos, Line: line, Pipe: pipe, List: list, ElseList: elseList}}
953 }
954
955 func (r *RangeNode) Copy() Node {
956 return r.tr.newRange(r.Pos, r.Line, r.Pipe.CopyPipe(), r.List.CopyList(), r.ElseList.CopyList())
957 }
958
959 // WithNode represents a {{with}} action and its commands.
960 type WithNode struct {
961 BranchNode
962 }
963
964 func (t *Tree) newWith(pos Pos, line int, pipe *PipeNode, list, elseList *ListNode) *WithNode {
965 return &WithNode{BranchNode{tr: t, NodeType: NodeWith, Pos: pos, Line: line, Pipe: pipe, List: list, ElseList: elseList}}
966 }
967
968 func (w *WithNode) Copy() Node {
969 return w.tr.newWith(w.Pos, w.Line, w.Pipe.CopyPipe(), w.List.CopyList(), w.ElseList.CopyList())
970 }
971
972 // TemplateNode represents a {{template}} action.
973 type TemplateNode struct {
974 NodeType
975 Pos
976 tr *Tree
977 Line int // The line number in the input. Deprecated: Kept for compatibility.
978 Name string // The name of the template (unquoted).
979 Pipe *PipeNode // The command to evaluate as dot for the template.
980 }
981
982 func (t *Tree) newTemplate(pos Pos, line int, name string, pipe *PipeNode) *TemplateNode {
983 return &TemplateNode{tr: t, NodeType: NodeTemplate, Pos: pos, Line: line, Name: name, Pipe: pipe}
984 }
985
986 func (t *TemplateNode) String() string {
987 var sb strings.Builder
988 t.writeTo(&sb)
989 return sb.String()
990 }
991
992 func (t *TemplateNode) writeTo(sb *strings.Builder) {
993 sb.WriteString("{{template ")
994 sb.WriteString(strconv.Quote(t.Name))
995 if t.Pipe != nil {
996 sb.WriteByte(' ')
997 t.Pipe.writeTo(sb)
998 }
999 sb.WriteString("}}")
1000 }
1001
1002 func (t *TemplateNode) tree() *Tree {
1003 return t.tr
1004 }
1005
1006 func (t *TemplateNode) Copy() Node {
1007 return t.tr.newTemplate(t.Pos, t.Line, t.Name, t.Pipe.CopyPipe())
1008 }