1
2
3
4
5
6
7 package parse
8
9 import (
10 "fmt"
11 "strconv"
12 "strings"
13 )
14
15 var textFormat = "%s"
16
17
18
19
20 type Node interface {
21 Type() NodeType
22 String() string
23
24
25
26 Copy() Node
27 Position() Pos
28
29
30 tree() *Tree
31
32 writeTo(*strings.Builder)
33 }
34
35
36 type NodeType int
37
38
39
40 type Pos int
41
42 func (p Pos) Position() Pos {
43 return p
44 }
45
46
47
48 func (t NodeType) Type() NodeType {
49 return t
50 }
51
52 const (
53 NodeText NodeType = iota
54 NodeAction
55 NodeBool
56 NodeChain
57 NodeCommand
58 NodeDot
59 nodeElse
60 nodeEnd
61 NodeField
62 NodeIdentifier
63 NodeIf
64 NodeList
65 NodeNil
66 NodeNumber
67 NodePipe
68 NodeRange
69 NodeString
70 NodeTemplate
71 NodeVariable
72 NodeWith
73 NodeComment
74 NodeBreak
75 NodeContinue
76 )
77
78
79
80
81 type ListNode struct {
82 NodeType
83 Pos
84 tr *Tree
85 Nodes []Node
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
128 type TextNode struct {
129 NodeType
130 Pos
131 tr *Tree
132 Text []byte
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
156 type CommentNode struct {
157 NodeType
158 Pos
159 tr *Tree
160 Text string
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
188 type PipeNode struct {
189 NodeType
190 Pos
191 tr *Tree
192 Line int
193 IsAssign bool
194 Decl []*VariableNode
195 Cmds []*CommandNode
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
255
256
257 type ActionNode struct {
258 NodeType
259 Pos
260 tr *Tree
261 Line int
262 Pipe *PipeNode
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
291 type CommandNode struct {
292 NodeType
293 Pos
294 tr *Tree
295 Args []Node
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
343 type IdentifierNode struct {
344 NodeType
345 Pos
346 tr *Tree
347 Ident string
348 }
349
350
351 func NewIdentifier(ident string) *IdentifierNode {
352 return &IdentifierNode{NodeType: NodeIdentifier, Ident: ident}
353 }
354
355
356
357
358 func (i *IdentifierNode) SetPos(pos Pos) *IdentifierNode {
359 i.Pos = pos
360 return i
361 }
362
363
364
365
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
388
389 type VariableNode struct {
390 NodeType
391 Pos
392 tr *Tree
393 Ident []string
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
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
436
437
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
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
470
471
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
492
493
494 type FieldNode struct {
495 NodeType
496 Pos
497 tr *Tree
498 Ident []string
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:], ".")}
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
527
528
529 type ChainNode struct {
530 NodeType
531 Pos
532 tr *Tree
533 Node Node
534 Field []string
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
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:]
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
582 type BoolNode struct {
583 NodeType
584 Pos
585 tr *Tree
586 True bool
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
613
614
615 type NumberNode struct {
616 NodeType
617 Pos
618 tr *Tree
619 IsInt bool
620 IsUint bool
621 IsFloat bool
622 IsComplex bool
623 Int64 int64
624 Uint64 uint64
625 Float64 float64
626 Complex128 complex128
627 Text string
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)
646 n.IsFloat = true
647 return n, nil
648 case itemComplex:
649
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
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
668 u, err := strconv.ParseUint(text, 0, 64)
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
679 n.Uint64 = u
680 }
681 }
682
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
693
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
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
717
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
748 return nn
749 }
750
751
752 type StringNode struct {
753 NodeType
754 Pos
755 tr *Tree
756 Quoted string
757 Text string
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
781
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
809 type elseNode struct {
810 NodeType
811 Pos
812 tr *Tree
813 Line int
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
841 type BranchNode struct {
842 NodeType
843 Pos
844 tr *Tree
845 Line int
846 Pipe *PipeNode
847 List *ListNode
848 ElseList *ListNode
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
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
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
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
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
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
973 type TemplateNode struct {
974 NodeType
975 Pos
976 tr *Tree
977 Line int
978 Name string
979 Pipe *PipeNode
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 }
1009
View as plain text