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