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 type CommandNode struct {
291 NodeType
292 Pos
293 tr *Tree
294 Args []Node
295 }
296
297 func (t *Tree) newCommand(pos Pos) *CommandNode {
298 return &CommandNode{tr: t, NodeType: NodeCommand, Pos: pos}
299 }
300
301 func (c *CommandNode) append(arg Node) {
302 c.Args = append(c.Args, arg)
303 }
304
305 func (c *CommandNode) String() string {
306 var sb strings.Builder
307 c.writeTo(&sb)
308 return sb.String()
309 }
310
311 func (c *CommandNode) writeTo(sb *strings.Builder) {
312 for i, arg := range c.Args {
313 if i > 0 {
314 sb.WriteByte(' ')
315 }
316 if arg, ok := arg.(*PipeNode); ok {
317 sb.WriteByte('(')
318 arg.writeTo(sb)
319 sb.WriteByte(')')
320 continue
321 }
322 arg.writeTo(sb)
323 }
324 }
325
326 func (c *CommandNode) tree() *Tree {
327 return c.tr
328 }
329
330 func (c *CommandNode) Copy() Node {
331 if c == nil {
332 return c
333 }
334 n := c.tr.newCommand(c.Pos)
335 for _, c := range c.Args {
336 n.append(c.Copy())
337 }
338 return n
339 }
340
341
342 type IdentifierNode struct {
343 NodeType
344 Pos
345 tr *Tree
346 Ident string
347 }
348
349
350 func NewIdentifier(ident string) *IdentifierNode {
351 return &IdentifierNode{NodeType: NodeIdentifier, Ident: ident}
352 }
353
354
355
356
357 func (i *IdentifierNode) SetPos(pos Pos) *IdentifierNode {
358 i.Pos = pos
359 return i
360 }
361
362
363
364
365 func (i *IdentifierNode) SetTree(t *Tree) *IdentifierNode {
366 i.tr = t
367 return i
368 }
369
370 func (i *IdentifierNode) String() string {
371 return i.Ident
372 }
373
374 func (i *IdentifierNode) writeTo(sb *strings.Builder) {
375 sb.WriteString(i.String())
376 }
377
378 func (i *IdentifierNode) tree() *Tree {
379 return i.tr
380 }
381
382 func (i *IdentifierNode) Copy() Node {
383 return NewIdentifier(i.Ident).SetTree(i.tr).SetPos(i.Pos)
384 }
385
386
387
388 type VariableNode struct {
389 NodeType
390 Pos
391 tr *Tree
392 Ident []string
393 }
394
395 func (t *Tree) newVariable(pos Pos, ident string) *VariableNode {
396 return &VariableNode{tr: t, NodeType: NodeVariable, Pos: pos, Ident: strings.Split(ident, ".")}
397 }
398
399 func (v *VariableNode) String() string {
400 var sb strings.Builder
401 v.writeTo(&sb)
402 return sb.String()
403 }
404
405 func (v *VariableNode) writeTo(sb *strings.Builder) {
406 for i, id := range v.Ident {
407 if i > 0 {
408 sb.WriteByte('.')
409 }
410 sb.WriteString(id)
411 }
412 }
413
414 func (v *VariableNode) tree() *Tree {
415 return v.tr
416 }
417
418 func (v *VariableNode) Copy() Node {
419 return &VariableNode{tr: v.tr, NodeType: NodeVariable, Pos: v.Pos, Ident: append([]string{}, v.Ident...)}
420 }
421
422
423 type DotNode struct {
424 NodeType
425 Pos
426 tr *Tree
427 }
428
429 func (t *Tree) newDot(pos Pos) *DotNode {
430 return &DotNode{tr: t, NodeType: NodeDot, Pos: pos}
431 }
432
433 func (d *DotNode) Type() NodeType {
434
435
436
437 return NodeDot
438 }
439
440 func (d *DotNode) String() string {
441 return "."
442 }
443
444 func (d *DotNode) writeTo(sb *strings.Builder) {
445 sb.WriteString(d.String())
446 }
447
448 func (d *DotNode) tree() *Tree {
449 return d.tr
450 }
451
452 func (d *DotNode) Copy() Node {
453 return d.tr.newDot(d.Pos)
454 }
455
456
457 type NilNode struct {
458 NodeType
459 Pos
460 tr *Tree
461 }
462
463 func (t *Tree) newNil(pos Pos) *NilNode {
464 return &NilNode{tr: t, NodeType: NodeNil, Pos: pos}
465 }
466
467 func (n *NilNode) Type() NodeType {
468
469
470
471 return NodeNil
472 }
473
474 func (n *NilNode) String() string {
475 return "nil"
476 }
477
478 func (n *NilNode) writeTo(sb *strings.Builder) {
479 sb.WriteString(n.String())
480 }
481
482 func (n *NilNode) tree() *Tree {
483 return n.tr
484 }
485
486 func (n *NilNode) Copy() Node {
487 return n.tr.newNil(n.Pos)
488 }
489
490
491
492
493 type FieldNode struct {
494 NodeType
495 Pos
496 tr *Tree
497 Ident []string
498 }
499
500 func (t *Tree) newField(pos Pos, ident string) *FieldNode {
501 return &FieldNode{tr: t, NodeType: NodeField, Pos: pos, Ident: strings.Split(ident[1:], ".")}
502 }
503
504 func (f *FieldNode) String() string {
505 var sb strings.Builder
506 f.writeTo(&sb)
507 return sb.String()
508 }
509
510 func (f *FieldNode) writeTo(sb *strings.Builder) {
511 for _, id := range f.Ident {
512 sb.WriteByte('.')
513 sb.WriteString(id)
514 }
515 }
516
517 func (f *FieldNode) tree() *Tree {
518 return f.tr
519 }
520
521 func (f *FieldNode) Copy() Node {
522 return &FieldNode{tr: f.tr, NodeType: NodeField, Pos: f.Pos, Ident: append([]string{}, f.Ident...)}
523 }
524
525
526
527
528 type ChainNode struct {
529 NodeType
530 Pos
531 tr *Tree
532 Node Node
533 Field []string
534 }
535
536 func (t *Tree) newChain(pos Pos, node Node) *ChainNode {
537 return &ChainNode{tr: t, NodeType: NodeChain, Pos: pos, Node: node}
538 }
539
540
541 func (c *ChainNode) Add(field string) {
542 if len(field) == 0 || field[0] != '.' {
543 panic("no dot in field")
544 }
545 field = field[1:]
546 if field == "" {
547 panic("empty field")
548 }
549 c.Field = append(c.Field, field)
550 }
551
552 func (c *ChainNode) String() string {
553 var sb strings.Builder
554 c.writeTo(&sb)
555 return sb.String()
556 }
557
558 func (c *ChainNode) writeTo(sb *strings.Builder) {
559 if _, ok := c.Node.(*PipeNode); ok {
560 sb.WriteByte('(')
561 c.Node.writeTo(sb)
562 sb.WriteByte(')')
563 } else {
564 c.Node.writeTo(sb)
565 }
566 for _, field := range c.Field {
567 sb.WriteByte('.')
568 sb.WriteString(field)
569 }
570 }
571
572 func (c *ChainNode) tree() *Tree {
573 return c.tr
574 }
575
576 func (c *ChainNode) Copy() Node {
577 return &ChainNode{tr: c.tr, NodeType: NodeChain, Pos: c.Pos, Node: c.Node, Field: append([]string{}, c.Field...)}
578 }
579
580
581 type BoolNode struct {
582 NodeType
583 Pos
584 tr *Tree
585 True bool
586 }
587
588 func (t *Tree) newBool(pos Pos, true bool) *BoolNode {
589 return &BoolNode{tr: t, NodeType: NodeBool, Pos: pos, True: true}
590 }
591
592 func (b *BoolNode) String() string {
593 if b.True {
594 return "true"
595 }
596 return "false"
597 }
598
599 func (b *BoolNode) writeTo(sb *strings.Builder) {
600 sb.WriteString(b.String())
601 }
602
603 func (b *BoolNode) tree() *Tree {
604 return b.tr
605 }
606
607 func (b *BoolNode) Copy() Node {
608 return b.tr.newBool(b.Pos, b.True)
609 }
610
611
612
613
614 type NumberNode struct {
615 NodeType
616 Pos
617 tr *Tree
618 IsInt bool
619 IsUint bool
620 IsFloat bool
621 IsComplex bool
622 Int64 int64
623 Uint64 uint64
624 Float64 float64
625 Complex128 complex128
626 Text string
627 }
628
629 func (t *Tree) newNumber(pos Pos, text string, typ itemType) (*NumberNode, error) {
630 n := &NumberNode{tr: t, NodeType: NodeNumber, Pos: pos, Text: text}
631 switch typ {
632 case itemCharConstant:
633 rune, _, tail, err := strconv.UnquoteChar(text[1:], text[0])
634 if err != nil {
635 return nil, err
636 }
637 if tail != "'" {
638 return nil, fmt.Errorf("malformed character constant: %s", text)
639 }
640 n.Int64 = int64(rune)
641 n.IsInt = true
642 n.Uint64 = uint64(rune)
643 n.IsUint = true
644 n.Float64 = float64(rune)
645 n.IsFloat = true
646 return n, nil
647 case itemComplex:
648
649 if _, err := fmt.Sscan(text, &n.Complex128); err != nil {
650 return nil, err
651 }
652 n.IsComplex = true
653 n.simplifyComplex()
654 return n, nil
655 }
656
657 if len(text) > 0 && text[len(text)-1] == 'i' {
658 f, err := strconv.ParseFloat(text[:len(text)-1], 64)
659 if err == nil {
660 n.IsComplex = true
661 n.Complex128 = complex(0, f)
662 n.simplifyComplex()
663 return n, nil
664 }
665 }
666
667 u, err := strconv.ParseUint(text, 0, 64)
668 if err == nil {
669 n.IsUint = true
670 n.Uint64 = u
671 }
672 i, err := strconv.ParseInt(text, 0, 64)
673 if err == nil {
674 n.IsInt = true
675 n.Int64 = i
676 if i == 0 {
677 n.IsUint = true
678 n.Uint64 = u
679 }
680 }
681
682 if n.IsInt {
683 n.IsFloat = true
684 n.Float64 = float64(n.Int64)
685 } else if n.IsUint {
686 n.IsFloat = true
687 n.Float64 = float64(n.Uint64)
688 } else {
689 f, err := strconv.ParseFloat(text, 64)
690 if err == nil {
691
692
693 if !strings.ContainsAny(text, ".eEpP") {
694 return nil, fmt.Errorf("integer overflow: %q", text)
695 }
696 n.IsFloat = true
697 n.Float64 = f
698
699 if !n.IsInt && float64(int64(f)) == f {
700 n.IsInt = true
701 n.Int64 = int64(f)
702 }
703 if !n.IsUint && float64(uint64(f)) == f {
704 n.IsUint = true
705 n.Uint64 = uint64(f)
706 }
707 }
708 }
709 if !n.IsInt && !n.IsUint && !n.IsFloat {
710 return nil, fmt.Errorf("illegal number syntax: %q", text)
711 }
712 return n, nil
713 }
714
715
716
717 func (n *NumberNode) simplifyComplex() {
718 n.IsFloat = imag(n.Complex128) == 0
719 if n.IsFloat {
720 n.Float64 = real(n.Complex128)
721 n.IsInt = float64(int64(n.Float64)) == n.Float64
722 if n.IsInt {
723 n.Int64 = int64(n.Float64)
724 }
725 n.IsUint = float64(uint64(n.Float64)) == n.Float64
726 if n.IsUint {
727 n.Uint64 = uint64(n.Float64)
728 }
729 }
730 }
731
732 func (n *NumberNode) String() string {
733 return n.Text
734 }
735
736 func (n *NumberNode) writeTo(sb *strings.Builder) {
737 sb.WriteString(n.String())
738 }
739
740 func (n *NumberNode) tree() *Tree {
741 return n.tr
742 }
743
744 func (n *NumberNode) Copy() Node {
745 nn := new(NumberNode)
746 *nn = *n
747 return nn
748 }
749
750
751 type StringNode struct {
752 NodeType
753 Pos
754 tr *Tree
755 Quoted string
756 Text string
757 }
758
759 func (t *Tree) newString(pos Pos, orig, text string) *StringNode {
760 return &StringNode{tr: t, NodeType: NodeString, Pos: pos, Quoted: orig, Text: text}
761 }
762
763 func (s *StringNode) String() string {
764 return s.Quoted
765 }
766
767 func (s *StringNode) writeTo(sb *strings.Builder) {
768 sb.WriteString(s.String())
769 }
770
771 func (s *StringNode) tree() *Tree {
772 return s.tr
773 }
774
775 func (s *StringNode) Copy() Node {
776 return s.tr.newString(s.Pos, s.Quoted, s.Text)
777 }
778
779
780
781 type endNode struct {
782 NodeType
783 Pos
784 tr *Tree
785 }
786
787 func (t *Tree) newEnd(pos Pos) *endNode {
788 return &endNode{tr: t, NodeType: nodeEnd, Pos: pos}
789 }
790
791 func (e *endNode) String() string {
792 return "{{end}}"
793 }
794
795 func (e *endNode) writeTo(sb *strings.Builder) {
796 sb.WriteString(e.String())
797 }
798
799 func (e *endNode) tree() *Tree {
800 return e.tr
801 }
802
803 func (e *endNode) Copy() Node {
804 return e.tr.newEnd(e.Pos)
805 }
806
807
808 type elseNode struct {
809 NodeType
810 Pos
811 tr *Tree
812 Line int
813 }
814
815 func (t *Tree) newElse(pos Pos, line int) *elseNode {
816 return &elseNode{tr: t, NodeType: nodeElse, Pos: pos, Line: line}
817 }
818
819 func (e *elseNode) Type() NodeType {
820 return nodeElse
821 }
822
823 func (e *elseNode) String() string {
824 return "{{else}}"
825 }
826
827 func (e *elseNode) writeTo(sb *strings.Builder) {
828 sb.WriteString(e.String())
829 }
830
831 func (e *elseNode) tree() *Tree {
832 return e.tr
833 }
834
835 func (e *elseNode) Copy() Node {
836 return e.tr.newElse(e.Pos, e.Line)
837 }
838
839
840 type BranchNode struct {
841 NodeType
842 Pos
843 tr *Tree
844 Line int
845 Pipe *PipeNode
846 List *ListNode
847 ElseList *ListNode
848 }
849
850 func (b *BranchNode) String() string {
851 var sb strings.Builder
852 b.writeTo(&sb)
853 return sb.String()
854 }
855
856 func (b *BranchNode) writeTo(sb *strings.Builder) {
857 name := ""
858 switch b.NodeType {
859 case NodeIf:
860 name = "if"
861 case NodeRange:
862 name = "range"
863 case NodeWith:
864 name = "with"
865 default:
866 panic("unknown branch type")
867 }
868 sb.WriteString("{{")
869 sb.WriteString(name)
870 sb.WriteByte(' ')
871 b.Pipe.writeTo(sb)
872 sb.WriteString("}}")
873 b.List.writeTo(sb)
874 if b.ElseList != nil {
875 sb.WriteString("{{else}}")
876 b.ElseList.writeTo(sb)
877 }
878 sb.WriteString("{{end}}")
879 }
880
881 func (b *BranchNode) tree() *Tree {
882 return b.tr
883 }
884
885 func (b *BranchNode) Copy() Node {
886 switch b.NodeType {
887 case NodeIf:
888 return b.tr.newIf(b.Pos, b.Line, b.Pipe, b.List, b.ElseList)
889 case NodeRange:
890 return b.tr.newRange(b.Pos, b.Line, b.Pipe, b.List, b.ElseList)
891 case NodeWith:
892 return b.tr.newWith(b.Pos, b.Line, b.Pipe, b.List, b.ElseList)
893 default:
894 panic("unknown branch type")
895 }
896 }
897
898
899 type IfNode struct {
900 BranchNode
901 }
902
903 func (t *Tree) newIf(pos Pos, line int, pipe *PipeNode, list, elseList *ListNode) *IfNode {
904 return &IfNode{BranchNode{tr: t, NodeType: NodeIf, Pos: pos, Line: line, Pipe: pipe, List: list, ElseList: elseList}}
905 }
906
907 func (i *IfNode) Copy() Node {
908 return i.tr.newIf(i.Pos, i.Line, i.Pipe.CopyPipe(), i.List.CopyList(), i.ElseList.CopyList())
909 }
910
911
912 type BreakNode struct {
913 tr *Tree
914 NodeType
915 Pos
916 Line int
917 }
918
919 func (t *Tree) newBreak(pos Pos, line int) *BreakNode {
920 return &BreakNode{tr: t, NodeType: NodeBreak, Pos: pos, Line: line}
921 }
922
923 func (b *BreakNode) Copy() Node { return b.tr.newBreak(b.Pos, b.Line) }
924 func (b *BreakNode) String() string { return "{{break}}" }
925 func (b *BreakNode) tree() *Tree { return b.tr }
926 func (b *BreakNode) writeTo(sb *strings.Builder) { sb.WriteString("{{break}}") }
927
928
929 type ContinueNode struct {
930 tr *Tree
931 NodeType
932 Pos
933 Line int
934 }
935
936 func (t *Tree) newContinue(pos Pos, line int) *ContinueNode {
937 return &ContinueNode{tr: t, NodeType: NodeContinue, Pos: pos, Line: line}
938 }
939
940 func (c *ContinueNode) Copy() Node { return c.tr.newContinue(c.Pos, c.Line) }
941 func (c *ContinueNode) String() string { return "{{continue}}" }
942 func (c *ContinueNode) tree() *Tree { return c.tr }
943 func (c *ContinueNode) writeTo(sb *strings.Builder) { sb.WriteString("{{continue}}") }
944
945
946 type RangeNode struct {
947 BranchNode
948 }
949
950 func (t *Tree) newRange(pos Pos, line int, pipe *PipeNode, list, elseList *ListNode) *RangeNode {
951 return &RangeNode{BranchNode{tr: t, NodeType: NodeRange, Pos: pos, Line: line, Pipe: pipe, List: list, ElseList: elseList}}
952 }
953
954 func (r *RangeNode) Copy() Node {
955 return r.tr.newRange(r.Pos, r.Line, r.Pipe.CopyPipe(), r.List.CopyList(), r.ElseList.CopyList())
956 }
957
958
959 type WithNode struct {
960 BranchNode
961 }
962
963 func (t *Tree) newWith(pos Pos, line int, pipe *PipeNode, list, elseList *ListNode) *WithNode {
964 return &WithNode{BranchNode{tr: t, NodeType: NodeWith, Pos: pos, Line: line, Pipe: pipe, List: list, ElseList: elseList}}
965 }
966
967 func (w *WithNode) Copy() Node {
968 return w.tr.newWith(w.Pos, w.Line, w.Pipe.CopyPipe(), w.List.CopyList(), w.ElseList.CopyList())
969 }
970
971
972 type TemplateNode struct {
973 NodeType
974 Pos
975 tr *Tree
976 Line int
977 Name string
978 Pipe *PipeNode
979 }
980
981 func (t *Tree) newTemplate(pos Pos, line int, name string, pipe *PipeNode) *TemplateNode {
982 return &TemplateNode{tr: t, NodeType: NodeTemplate, Pos: pos, Line: line, Name: name, Pipe: pipe}
983 }
984
985 func (t *TemplateNode) String() string {
986 var sb strings.Builder
987 t.writeTo(&sb)
988 return sb.String()
989 }
990
991 func (t *TemplateNode) writeTo(sb *strings.Builder) {
992 sb.WriteString("{{template ")
993 sb.WriteString(strconv.Quote(t.Name))
994 if t.Pipe != nil {
995 sb.WriteByte(' ')
996 t.Pipe.writeTo(sb)
997 }
998 sb.WriteString("}}")
999 }
1000
1001 func (t *TemplateNode) tree() *Tree {
1002 return t.tr
1003 }
1004
1005 func (t *TemplateNode) Copy() Node {
1006 return t.tr.newTemplate(t.Pos, t.Line, t.Name, t.Pipe.CopyPipe())
1007 }
1008
View as plain text