Source file src/text/template/parse/node.go
1
2
3
4
5
6
7 package parse
8
9 import (
10 "bytes"
11 "fmt"
12 "strconv"
13 "strings"
14 )
15
16 var textFormat = "%s"
17
18
19
20
21 type Node interface {
22 Type() NodeType
23 String() string
24
25
26
27 Copy() Node
28 Position() Pos
29
30
31 tree() *Tree
32 }
33
34
35 type NodeType int
36
37
38
39 type Pos int
40
41 func (p Pos) Position() Pos {
42 return p
43 }
44
45
46
47 func (t NodeType) Type() NodeType {
48 return t
49 }
50
51 const (
52 NodeText NodeType = iota
53 NodeAction
54 NodeBool
55 NodeChain
56 NodeCommand
57 NodeDot
58 nodeElse
59 nodeEnd
60 NodeField
61 NodeIdentifier
62 NodeIf
63 NodeList
64 NodeNil
65 NodeNumber
66 NodePipe
67 NodeRange
68 NodeString
69 NodeTemplate
70 NodeVariable
71 NodeWith
72 )
73
74
75
76
77 type ListNode struct {
78 NodeType
79 Pos
80 tr *Tree
81 Nodes []Node
82 }
83
84 func (t *Tree) newList(pos Pos) *ListNode {
85 return &ListNode{tr: t, NodeType: NodeList, Pos: pos}
86 }
87
88 func (l *ListNode) append(n Node) {
89 l.Nodes = append(l.Nodes, n)
90 }
91
92 func (l *ListNode) tree() *Tree {
93 return l.tr
94 }
95
96 func (l *ListNode) String() string {
97 b := new(bytes.Buffer)
98 for _, n := range l.Nodes {
99 fmt.Fprint(b, n)
100 }
101 return b.String()
102 }
103
104 func (l *ListNode) CopyList() *ListNode {
105 if l == nil {
106 return l
107 }
108 n := l.tr.newList(l.Pos)
109 for _, elem := range l.Nodes {
110 n.append(elem.Copy())
111 }
112 return n
113 }
114
115 func (l *ListNode) Copy() Node {
116 return l.CopyList()
117 }
118
119
120 type TextNode struct {
121 NodeType
122 Pos
123 tr *Tree
124 Text []byte
125 }
126
127 func (t *Tree) newText(pos Pos, text string) *TextNode {
128 return &TextNode{tr: t, NodeType: NodeText, Pos: pos, Text: []byte(text)}
129 }
130
131 func (t *TextNode) String() string {
132 return fmt.Sprintf(textFormat, t.Text)
133 }
134
135 func (t *TextNode) tree() *Tree {
136 return t.tr
137 }
138
139 func (t *TextNode) Copy() Node {
140 return &TextNode{tr: t.tr, NodeType: NodeText, Pos: t.Pos, Text: append([]byte{}, t.Text...)}
141 }
142
143
144 type PipeNode struct {
145 NodeType
146 Pos
147 tr *Tree
148 Line int
149 IsAssign bool
150 Decl []*VariableNode
151 Cmds []*CommandNode
152 }
153
154 func (t *Tree) newPipeline(pos Pos, line int, vars []*VariableNode) *PipeNode {
155 return &PipeNode{tr: t, NodeType: NodePipe, Pos: pos, Line: line, Decl: vars}
156 }
157
158 func (p *PipeNode) append(command *CommandNode) {
159 p.Cmds = append(p.Cmds, command)
160 }
161
162 func (p *PipeNode) String() string {
163 s := ""
164 if len(p.Decl) > 0 {
165 for i, v := range p.Decl {
166 if i > 0 {
167 s += ", "
168 }
169 s += v.String()
170 }
171 s += " := "
172 }
173 for i, c := range p.Cmds {
174 if i > 0 {
175 s += " | "
176 }
177 s += c.String()
178 }
179 return s
180 }
181
182 func (p *PipeNode) tree() *Tree {
183 return p.tr
184 }
185
186 func (p *PipeNode) CopyPipe() *PipeNode {
187 if p == nil {
188 return p
189 }
190 var vars []*VariableNode
191 for _, d := range p.Decl {
192 vars = append(vars, d.Copy().(*VariableNode))
193 }
194 n := p.tr.newPipeline(p.Pos, p.Line, vars)
195 n.IsAssign = p.IsAssign
196 for _, c := range p.Cmds {
197 n.append(c.Copy().(*CommandNode))
198 }
199 return n
200 }
201
202 func (p *PipeNode) Copy() Node {
203 return p.CopyPipe()
204 }
205
206
207
208
209 type ActionNode struct {
210 NodeType
211 Pos
212 tr *Tree
213 Line int
214 Pipe *PipeNode
215 }
216
217 func (t *Tree) newAction(pos Pos, line int, pipe *PipeNode) *ActionNode {
218 return &ActionNode{tr: t, NodeType: NodeAction, Pos: pos, Line: line, Pipe: pipe}
219 }
220
221 func (a *ActionNode) String() string {
222 return fmt.Sprintf("{{%s}}", a.Pipe)
223
224 }
225
226 func (a *ActionNode) tree() *Tree {
227 return a.tr
228 }
229
230 func (a *ActionNode) Copy() Node {
231 return a.tr.newAction(a.Pos, a.Line, a.Pipe.CopyPipe())
232
233 }
234
235
236 type CommandNode struct {
237 NodeType
238 Pos
239 tr *Tree
240 Args []Node
241 }
242
243 func (t *Tree) newCommand(pos Pos) *CommandNode {
244 return &CommandNode{tr: t, NodeType: NodeCommand, Pos: pos}
245 }
246
247 func (c *CommandNode) append(arg Node) {
248 c.Args = append(c.Args, arg)
249 }
250
251 func (c *CommandNode) String() string {
252 s := ""
253 for i, arg := range c.Args {
254 if i > 0 {
255 s += " "
256 }
257 if arg, ok := arg.(*PipeNode); ok {
258 s += "(" + arg.String() + ")"
259 continue
260 }
261 s += arg.String()
262 }
263 return s
264 }
265
266 func (c *CommandNode) tree() *Tree {
267 return c.tr
268 }
269
270 func (c *CommandNode) Copy() Node {
271 if c == nil {
272 return c
273 }
274 n := c.tr.newCommand(c.Pos)
275 for _, c := range c.Args {
276 n.append(c.Copy())
277 }
278 return n
279 }
280
281
282 type IdentifierNode struct {
283 NodeType
284 Pos
285 tr *Tree
286 Ident string
287 }
288
289
290 func NewIdentifier(ident string) *IdentifierNode {
291 return &IdentifierNode{NodeType: NodeIdentifier, Ident: ident}
292 }
293
294
295
296
297 func (i *IdentifierNode) SetPos(pos Pos) *IdentifierNode {
298 i.Pos = pos
299 return i
300 }
301
302
303
304
305 func (i *IdentifierNode) SetTree(t *Tree) *IdentifierNode {
306 i.tr = t
307 return i
308 }
309
310 func (i *IdentifierNode) String() string {
311 return i.Ident
312 }
313
314 func (i *IdentifierNode) tree() *Tree {
315 return i.tr
316 }
317
318 func (i *IdentifierNode) Copy() Node {
319 return NewIdentifier(i.Ident).SetTree(i.tr).SetPos(i.Pos)
320 }
321
322
323
324 type VariableNode struct {
325 NodeType
326 Pos
327 tr *Tree
328 Ident []string
329 }
330
331 func (t *Tree) newVariable(pos Pos, ident string) *VariableNode {
332 return &VariableNode{tr: t, NodeType: NodeVariable, Pos: pos, Ident: strings.Split(ident, ".")}
333 }
334
335 func (v *VariableNode) String() string {
336 s := ""
337 for i, id := range v.Ident {
338 if i > 0 {
339 s += "."
340 }
341 s += id
342 }
343 return s
344 }
345
346 func (v *VariableNode) tree() *Tree {
347 return v.tr
348 }
349
350 func (v *VariableNode) Copy() Node {
351 return &VariableNode{tr: v.tr, NodeType: NodeVariable, Pos: v.Pos, Ident: append([]string{}, v.Ident...)}
352 }
353
354
355 type DotNode struct {
356 NodeType
357 Pos
358 tr *Tree
359 }
360
361 func (t *Tree) newDot(pos Pos) *DotNode {
362 return &DotNode{tr: t, NodeType: NodeDot, Pos: pos}
363 }
364
365 func (d *DotNode) Type() NodeType {
366
367
368
369 return NodeDot
370 }
371
372 func (d *DotNode) String() string {
373 return "."
374 }
375
376 func (d *DotNode) tree() *Tree {
377 return d.tr
378 }
379
380 func (d *DotNode) Copy() Node {
381 return d.tr.newDot(d.Pos)
382 }
383
384
385 type NilNode struct {
386 NodeType
387 Pos
388 tr *Tree
389 }
390
391 func (t *Tree) newNil(pos Pos) *NilNode {
392 return &NilNode{tr: t, NodeType: NodeNil, Pos: pos}
393 }
394
395 func (n *NilNode) Type() NodeType {
396
397
398
399 return NodeNil
400 }
401
402 func (n *NilNode) String() string {
403 return "nil"
404 }
405
406 func (n *NilNode) tree() *Tree {
407 return n.tr
408 }
409
410 func (n *NilNode) Copy() Node {
411 return n.tr.newNil(n.Pos)
412 }
413
414
415
416
417 type FieldNode struct {
418 NodeType
419 Pos
420 tr *Tree
421 Ident []string
422 }
423
424 func (t *Tree) newField(pos Pos, ident string) *FieldNode {
425 return &FieldNode{tr: t, NodeType: NodeField, Pos: pos, Ident: strings.Split(ident[1:], ".")}
426 }
427
428 func (f *FieldNode) String() string {
429 s := ""
430 for _, id := range f.Ident {
431 s += "." + id
432 }
433 return s
434 }
435
436 func (f *FieldNode) tree() *Tree {
437 return f.tr
438 }
439
440 func (f *FieldNode) Copy() Node {
441 return &FieldNode{tr: f.tr, NodeType: NodeField, Pos: f.Pos, Ident: append([]string{}, f.Ident...)}
442 }
443
444
445
446
447 type ChainNode struct {
448 NodeType
449 Pos
450 tr *Tree
451 Node Node
452 Field []string
453 }
454
455 func (t *Tree) newChain(pos Pos, node Node) *ChainNode {
456 return &ChainNode{tr: t, NodeType: NodeChain, Pos: pos, Node: node}
457 }
458
459
460 func (c *ChainNode) Add(field string) {
461 if len(field) == 0 || field[0] != '.' {
462 panic("no dot in field")
463 }
464 field = field[1:]
465 if field == "" {
466 panic("empty field")
467 }
468 c.Field = append(c.Field, field)
469 }
470
471 func (c *ChainNode) String() string {
472 s := c.Node.String()
473 if _, ok := c.Node.(*PipeNode); ok {
474 s = "(" + s + ")"
475 }
476 for _, field := range c.Field {
477 s += "." + field
478 }
479 return s
480 }
481
482 func (c *ChainNode) tree() *Tree {
483 return c.tr
484 }
485
486 func (c *ChainNode) Copy() Node {
487 return &ChainNode{tr: c.tr, NodeType: NodeChain, Pos: c.Pos, Node: c.Node, Field: append([]string{}, c.Field...)}
488 }
489
490
491 type BoolNode struct {
492 NodeType
493 Pos
494 tr *Tree
495 True bool
496 }
497
498 func (t *Tree) newBool(pos Pos, true bool) *BoolNode {
499 return &BoolNode{tr: t, NodeType: NodeBool, Pos: pos, True: true}
500 }
501
502 func (b *BoolNode) String() string {
503 if b.True {
504 return "true"
505 }
506 return "false"
507 }
508
509 func (b *BoolNode) tree() *Tree {
510 return b.tr
511 }
512
513 func (b *BoolNode) Copy() Node {
514 return b.tr.newBool(b.Pos, b.True)
515 }
516
517
518
519
520 type NumberNode struct {
521 NodeType
522 Pos
523 tr *Tree
524 IsInt bool
525 IsUint bool
526 IsFloat bool
527 IsComplex bool
528 Int64 int64
529 Uint64 uint64
530 Float64 float64
531 Complex128 complex128
532 Text string
533 }
534
535 func (t *Tree) newNumber(pos Pos, text string, typ itemType) (*NumberNode, error) {
536 n := &NumberNode{tr: t, NodeType: NodeNumber, Pos: pos, Text: text}
537 switch typ {
538 case itemCharConstant:
539 rune, _, tail, err := strconv.UnquoteChar(text[1:], text[0])
540 if err != nil {
541 return nil, err
542 }
543 if tail != "'" {
544 return nil, fmt.Errorf("malformed character constant: %s", text)
545 }
546 n.Int64 = int64(rune)
547 n.IsInt = true
548 n.Uint64 = uint64(rune)
549 n.IsUint = true
550 n.Float64 = float64(rune)
551 n.IsFloat = true
552 return n, nil
553 case itemComplex:
554
555 if _, err := fmt.Sscan(text, &n.Complex128); err != nil {
556 return nil, err
557 }
558 n.IsComplex = true
559 n.simplifyComplex()
560 return n, nil
561 }
562
563 if len(text) > 0 && text[len(text)-1] == 'i' {
564 f, err := strconv.ParseFloat(text[:len(text)-1], 64)
565 if err == nil {
566 n.IsComplex = true
567 n.Complex128 = complex(0, f)
568 n.simplifyComplex()
569 return n, nil
570 }
571 }
572
573 u, err := strconv.ParseUint(text, 0, 64)
574 if err == nil {
575 n.IsUint = true
576 n.Uint64 = u
577 }
578 i, err := strconv.ParseInt(text, 0, 64)
579 if err == nil {
580 n.IsInt = true
581 n.Int64 = i
582 if i == 0 {
583 n.IsUint = true
584 n.Uint64 = u
585 }
586 }
587
588 if n.IsInt {
589 n.IsFloat = true
590 n.Float64 = float64(n.Int64)
591 } else if n.IsUint {
592 n.IsFloat = true
593 n.Float64 = float64(n.Uint64)
594 } else {
595 f, err := strconv.ParseFloat(text, 64)
596 if err == nil {
597
598
599 if !strings.ContainsAny(text, ".eEpP") {
600 return nil, fmt.Errorf("integer overflow: %q", text)
601 }
602 n.IsFloat = true
603 n.Float64 = f
604
605 if !n.IsInt && float64(int64(f)) == f {
606 n.IsInt = true
607 n.Int64 = int64(f)
608 }
609 if !n.IsUint && float64(uint64(f)) == f {
610 n.IsUint = true
611 n.Uint64 = uint64(f)
612 }
613 }
614 }
615 if !n.IsInt && !n.IsUint && !n.IsFloat {
616 return nil, fmt.Errorf("illegal number syntax: %q", text)
617 }
618 return n, nil
619 }
620
621
622
623 func (n *NumberNode) simplifyComplex() {
624 n.IsFloat = imag(n.Complex128) == 0
625 if n.IsFloat {
626 n.Float64 = real(n.Complex128)
627 n.IsInt = float64(int64(n.Float64)) == n.Float64
628 if n.IsInt {
629 n.Int64 = int64(n.Float64)
630 }
631 n.IsUint = float64(uint64(n.Float64)) == n.Float64
632 if n.IsUint {
633 n.Uint64 = uint64(n.Float64)
634 }
635 }
636 }
637
638 func (n *NumberNode) String() string {
639 return n.Text
640 }
641
642 func (n *NumberNode) tree() *Tree {
643 return n.tr
644 }
645
646 func (n *NumberNode) Copy() Node {
647 nn := new(NumberNode)
648 *nn = *n
649 return nn
650 }
651
652
653 type StringNode struct {
654 NodeType
655 Pos
656 tr *Tree
657 Quoted string
658 Text string
659 }
660
661 func (t *Tree) newString(pos Pos, orig, text string) *StringNode {
662 return &StringNode{tr: t, NodeType: NodeString, Pos: pos, Quoted: orig, Text: text}
663 }
664
665 func (s *StringNode) String() string {
666 return s.Quoted
667 }
668
669 func (s *StringNode) tree() *Tree {
670 return s.tr
671 }
672
673 func (s *StringNode) Copy() Node {
674 return s.tr.newString(s.Pos, s.Quoted, s.Text)
675 }
676
677
678
679 type endNode struct {
680 NodeType
681 Pos
682 tr *Tree
683 }
684
685 func (t *Tree) newEnd(pos Pos) *endNode {
686 return &endNode{tr: t, NodeType: nodeEnd, Pos: pos}
687 }
688
689 func (e *endNode) String() string {
690 return "{{end}}"
691 }
692
693 func (e *endNode) tree() *Tree {
694 return e.tr
695 }
696
697 func (e *endNode) Copy() Node {
698 return e.tr.newEnd(e.Pos)
699 }
700
701
702 type elseNode struct {
703 NodeType
704 Pos
705 tr *Tree
706 Line int
707 }
708
709 func (t *Tree) newElse(pos Pos, line int) *elseNode {
710 return &elseNode{tr: t, NodeType: nodeElse, Pos: pos, Line: line}
711 }
712
713 func (e *elseNode) Type() NodeType {
714 return nodeElse
715 }
716
717 func (e *elseNode) String() string {
718 return "{{else}}"
719 }
720
721 func (e *elseNode) tree() *Tree {
722 return e.tr
723 }
724
725 func (e *elseNode) Copy() Node {
726 return e.tr.newElse(e.Pos, e.Line)
727 }
728
729
730 type BranchNode struct {
731 NodeType
732 Pos
733 tr *Tree
734 Line int
735 Pipe *PipeNode
736 List *ListNode
737 ElseList *ListNode
738 }
739
740 func (b *BranchNode) String() string {
741 name := ""
742 switch b.NodeType {
743 case NodeIf:
744 name = "if"
745 case NodeRange:
746 name = "range"
747 case NodeWith:
748 name = "with"
749 default:
750 panic("unknown branch type")
751 }
752 if b.ElseList != nil {
753 return fmt.Sprintf("{{%s %s}}%s{{else}}%s{{end}}", name, b.Pipe, b.List, b.ElseList)
754 }
755 return fmt.Sprintf("{{%s %s}}%s{{end}}", name, b.Pipe, b.List)
756 }
757
758 func (b *BranchNode) tree() *Tree {
759 return b.tr
760 }
761
762 func (b *BranchNode) Copy() Node {
763 switch b.NodeType {
764 case NodeIf:
765 return b.tr.newIf(b.Pos, b.Line, b.Pipe, b.List, b.ElseList)
766 case NodeRange:
767 return b.tr.newRange(b.Pos, b.Line, b.Pipe, b.List, b.ElseList)
768 case NodeWith:
769 return b.tr.newWith(b.Pos, b.Line, b.Pipe, b.List, b.ElseList)
770 default:
771 panic("unknown branch type")
772 }
773 }
774
775
776 type IfNode struct {
777 BranchNode
778 }
779
780 func (t *Tree) newIf(pos Pos, line int, pipe *PipeNode, list, elseList *ListNode) *IfNode {
781 return &IfNode{BranchNode{tr: t, NodeType: NodeIf, Pos: pos, Line: line, Pipe: pipe, List: list, ElseList: elseList}}
782 }
783
784 func (i *IfNode) Copy() Node {
785 return i.tr.newIf(i.Pos, i.Line, i.Pipe.CopyPipe(), i.List.CopyList(), i.ElseList.CopyList())
786 }
787
788
789 type RangeNode struct {
790 BranchNode
791 }
792
793 func (t *Tree) newRange(pos Pos, line int, pipe *PipeNode, list, elseList *ListNode) *RangeNode {
794 return &RangeNode{BranchNode{tr: t, NodeType: NodeRange, Pos: pos, Line: line, Pipe: pipe, List: list, ElseList: elseList}}
795 }
796
797 func (r *RangeNode) Copy() Node {
798 return r.tr.newRange(r.Pos, r.Line, r.Pipe.CopyPipe(), r.List.CopyList(), r.ElseList.CopyList())
799 }
800
801
802 type WithNode struct {
803 BranchNode
804 }
805
806 func (t *Tree) newWith(pos Pos, line int, pipe *PipeNode, list, elseList *ListNode) *WithNode {
807 return &WithNode{BranchNode{tr: t, NodeType: NodeWith, Pos: pos, Line: line, Pipe: pipe, List: list, ElseList: elseList}}
808 }
809
810 func (w *WithNode) Copy() Node {
811 return w.tr.newWith(w.Pos, w.Line, w.Pipe.CopyPipe(), w.List.CopyList(), w.ElseList.CopyList())
812 }
813
814
815 type TemplateNode struct {
816 NodeType
817 Pos
818 tr *Tree
819 Line int
820 Name string
821 Pipe *PipeNode
822 }
823
824 func (t *Tree) newTemplate(pos Pos, line int, name string, pipe *PipeNode) *TemplateNode {
825 return &TemplateNode{tr: t, NodeType: NodeTemplate, Pos: pos, Line: line, Name: name, Pipe: pipe}
826 }
827
828 func (t *TemplateNode) String() string {
829 if t.Pipe == nil {
830 return fmt.Sprintf("{{template %q}}", t.Name)
831 }
832 return fmt.Sprintf("{{template %q %s}}", t.Name, t.Pipe)
833 }
834
835 func (t *TemplateNode) tree() *Tree {
836 return t.tr
837 }
838
839 func (t *TemplateNode) Copy() Node {
840 return t.tr.newTemplate(t.Pos, t.Line, t.Name, t.Pipe.CopyPipe())
841 }
842
View as plain text