github.com/stingnevermore/go@v0.0.0-20180120041312-3810f5bfed72/src/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 "bytes" 11 "fmt" 12 "strconv" 13 "strings" 14 ) 15 16 var textFormat = "%s" // Changed to "%q" in tests for better error messages. 17 18 // A Node is an element in the parse tree. The interface is trivial. 19 // The interface contains an unexported method so that only 20 // types local to this package can satisfy it. 21 type Node interface { 22 Type() NodeType 23 String() string 24 // Copy does a deep copy of the Node and all its components. 25 // To avoid type assertions, some XxxNodes also have specialized 26 // CopyXxx methods that return *XxxNode. 27 Copy() Node 28 Position() Pos // byte position of start of node in full original input string 29 // tree returns the containing *Tree. 30 // It is unexported so all implementations of Node are in this package. 31 tree() *Tree 32 } 33 34 // NodeType identifies the type of a parse tree node. 35 type NodeType int 36 37 // Pos represents a byte position in the original input text from which 38 // this template was parsed. 39 type Pos int 40 41 func (p Pos) Position() Pos { 42 return p 43 } 44 45 // Type returns itself and provides an easy default implementation 46 // for embedding in a Node. Embedded in all non-trivial Nodes. 47 func (t NodeType) Type() NodeType { 48 return t 49 } 50 51 const ( 52 NodeText NodeType = iota // Plain text. 53 NodeAction // A non-control action such as a field evaluation. 54 NodeBool // A boolean constant. 55 NodeChain // A sequence of field accesses. 56 NodeCommand // An element of a pipeline. 57 NodeDot // The cursor, dot. 58 nodeElse // An else action. Not added to tree. 59 nodeEnd // An end action. Not added to tree. 60 NodeField // A field or method name. 61 NodeIdentifier // An identifier; always a function name. 62 NodeIf // An if action. 63 NodeList // A list of Nodes. 64 NodeNil // An untyped nil constant. 65 NodeNumber // A numerical constant. 66 NodePipe // A pipeline of commands. 67 NodeRange // A range action. 68 NodeString // A string constant. 69 NodeTemplate // A template invocation action. 70 NodeVariable // A $ variable. 71 NodeWith // A with action. 72 NodeBreak // A break action. 73 NodeContinue // A continue action. 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 b := new(bytes.Buffer) 100 for _, n := range l.Nodes { 101 fmt.Fprint(b, n) 102 } 103 return b.String() 104 } 105 106 func (l *ListNode) CopyList() *ListNode { 107 if l == nil { 108 return l 109 } 110 n := l.tr.newList(l.Pos) 111 for _, elem := range l.Nodes { 112 n.append(elem.Copy()) 113 } 114 return n 115 } 116 117 func (l *ListNode) Copy() Node { 118 return l.CopyList() 119 } 120 121 // TextNode holds plain text. 122 type TextNode struct { 123 NodeType 124 Pos 125 tr *Tree 126 Text []byte // The text; may span newlines. 127 } 128 129 func (t *Tree) newText(pos Pos, text string) *TextNode { 130 return &TextNode{tr: t, NodeType: NodeText, Pos: pos, Text: []byte(text)} 131 } 132 133 func (t *TextNode) String() string { 134 return fmt.Sprintf(textFormat, t.Text) 135 } 136 137 func (t *TextNode) tree() *Tree { 138 return t.tr 139 } 140 141 func (t *TextNode) Copy() Node { 142 return &TextNode{tr: t.tr, NodeType: NodeText, Pos: t.Pos, Text: append([]byte{}, t.Text...)} 143 } 144 145 // PipeNode holds a pipeline with optional declaration 146 type PipeNode struct { 147 NodeType 148 Pos 149 tr *Tree 150 Line int // The line number in the input. Deprecated: Kept for compatibility. 151 Decl []*VariableNode // Variable declarations in lexical order. 152 Cmds []*CommandNode // The commands in lexical order. 153 } 154 155 func (t *Tree) newPipeline(pos Pos, line int, decl []*VariableNode) *PipeNode { 156 return &PipeNode{tr: t, NodeType: NodePipe, Pos: pos, Line: line, Decl: decl} 157 } 158 159 func (p *PipeNode) append(command *CommandNode) { 160 p.Cmds = append(p.Cmds, command) 161 } 162 163 func (p *PipeNode) String() string { 164 s := "" 165 if len(p.Decl) > 0 { 166 for i, v := range p.Decl { 167 if i > 0 { 168 s += ", " 169 } 170 s += v.String() 171 } 172 s += " := " 173 } 174 for i, c := range p.Cmds { 175 if i > 0 { 176 s += " | " 177 } 178 s += c.String() 179 } 180 return s 181 } 182 183 func (p *PipeNode) tree() *Tree { 184 return p.tr 185 } 186 187 func (p *PipeNode) CopyPipe() *PipeNode { 188 if p == nil { 189 return p 190 } 191 var decl []*VariableNode 192 for _, d := range p.Decl { 193 decl = append(decl, d.Copy().(*VariableNode)) 194 } 195 n := p.tr.newPipeline(p.Pos, p.Line, decl) 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 // ActionNode holds an action (something bounded by delimiters). 207 // Control actions have their own nodes; ActionNode represents simple 208 // ones such as field evaluations and parenthesized pipelines. 209 type ActionNode struct { 210 NodeType 211 Pos 212 tr *Tree 213 Line int // The line number in the input. Deprecated: Kept for compatibility. 214 Pipe *PipeNode // The pipeline in the action. 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 // CommandNode holds a command (a pipeline inside an evaluating action). 236 type CommandNode struct { 237 NodeType 238 Pos 239 tr *Tree 240 Args []Node // Arguments in lexical order: Identifier, field, or constant. 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 // IdentifierNode holds an identifier. 282 type IdentifierNode struct { 283 NodeType 284 Pos 285 tr *Tree 286 Ident string // The identifier's name. 287 } 288 289 // NewIdentifier returns a new IdentifierNode with the given identifier name. 290 func NewIdentifier(ident string) *IdentifierNode { 291 return &IdentifierNode{NodeType: NodeIdentifier, Ident: ident} 292 } 293 294 // SetPos sets the position. NewIdentifier is a public method so we can't modify its signature. 295 // Chained for convenience. 296 // TODO: fix one day? 297 func (i *IdentifierNode) SetPos(pos Pos) *IdentifierNode { 298 i.Pos = pos 299 return i 300 } 301 302 // SetTree sets the parent tree for the node. NewIdentifier is a public method so we can't modify its signature. 303 // Chained for convenience. 304 // TODO: fix one day? 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 // VariableNode holds a list of variable names, possibly with chained field 323 // accesses. The dollar sign is part of the (first) name. 324 type VariableNode struct { 325 NodeType 326 Pos 327 tr *Tree 328 Ident []string // Variable name and fields in lexical order. 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 // DotNode holds the special identifier '.'. 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 // Override method on embedded NodeType for API compatibility. 367 // TODO: Not really a problem; could change API without effect but 368 // api tool complains. 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 // NilNode holds the special identifier 'nil' representing an untyped nil constant. 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 // Override method on embedded NodeType for API compatibility. 397 // TODO: Not really a problem; could change API without effect but 398 // api tool complains. 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 // FieldNode holds a field (identifier starting with '.'). 415 // The names may be chained ('.x.y'). 416 // The period is dropped from each ident. 417 type FieldNode struct { 418 NodeType 419 Pos 420 tr *Tree 421 Ident []string // The identifiers in lexical order. 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:], ".")} // [1:] to drop leading period 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 // ChainNode holds a term followed by a chain of field accesses (identifier starting with '.'). 445 // The names may be chained ('.x.y'). 446 // The periods are dropped from each ident. 447 type ChainNode struct { 448 NodeType 449 Pos 450 tr *Tree 451 Node Node 452 Field []string // The identifiers in lexical order. 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 // Add adds the named field (which should start with a period) to the end of the chain. 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:] // Remove leading dot. 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 // BoolNode holds a boolean constant. 491 type BoolNode struct { 492 NodeType 493 Pos 494 tr *Tree 495 True bool // The value of the boolean constant. 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 // NumberNode holds a number: signed or unsigned integer, float, or complex. 518 // The value is parsed and stored under all the types that can represent the value. 519 // This simulates in a small amount of code the behavior of Go's ideal constants. 520 type NumberNode struct { 521 NodeType 522 Pos 523 tr *Tree 524 IsInt bool // Number has an integral value. 525 IsUint bool // Number has an unsigned integral value. 526 IsFloat bool // Number has a floating-point value. 527 IsComplex bool // Number is complex. 528 Int64 int64 // The signed integer value. 529 Uint64 uint64 // The unsigned integer value. 530 Float64 float64 // The floating-point value. 531 Complex128 complex128 // The complex value. 532 Text string // The original textual representation from the input. 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) // odd but those are the rules. 551 n.IsFloat = true 552 return n, nil 553 case itemComplex: 554 // fmt.Sscan can parse the pair, so let it do the work. 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 // Imaginary constants can only be complex unless they are zero. 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 // Do integer test first so we get 0x123 etc. 573 u, err := strconv.ParseUint(text, 0, 64) // will fail for -0; fixed below. 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 // in case of -0. 584 n.Uint64 = u 585 } 586 } 587 // If an integer extraction succeeded, promote the float. 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 // If we parsed it as a float but it looks like an integer, 598 // it's a huge number too large to fit in an int. Reject it. 599 if !strings.ContainsAny(text, ".eE") { 600 return nil, fmt.Errorf("integer overflow: %q", text) 601 } 602 n.IsFloat = true 603 n.Float64 = f 604 // If a floating-point extraction succeeded, extract the int if needed. 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 // simplifyComplex pulls out any other types that are represented by the complex number. 622 // These all require that the imaginary part be zero. 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 // Easy, fast, correct. 649 return nn 650 } 651 652 // StringNode holds a string constant. The value has been "unquoted". 653 type StringNode struct { 654 NodeType 655 Pos 656 tr *Tree 657 Quoted string // The original text of the string, with quotes. 658 Text string // The string, after quote processing. 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 // endNode represents an {{end}} action. 678 // It does not appear in the final parse tree. 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 // elseNode represents an {{else}} action. Does not appear in the final tree. 702 type elseNode struct { 703 NodeType 704 Pos 705 tr *Tree 706 Line int // The line number in the input. Deprecated: Kept for compatibility. 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 // BranchNode is the common representation of if, range, and with. 730 type BranchNode struct { 731 NodeType 732 Pos 733 tr *Tree 734 Line int // The line number in the input. Deprecated: Kept for compatibility. 735 Pipe *PipeNode // The pipeline to be evaluated. 736 List *ListNode // What to execute if the value is non-empty. 737 ElseList *ListNode // What to execute if the value is empty (nil if absent). 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 // IfNode represents an {{if}} action and its commands. 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 // RangeNode represents a {{range}} action and its commands. 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 // BreakNode represents a {{break}} action. 802 type BreakNode struct { 803 NodeType 804 Pos 805 tr *Tree 806 } 807 808 func (t *Tree) newBreak(pos Pos) *BreakNode { 809 return &BreakNode{NodeType: NodeBreak, Pos: pos, tr: t} 810 } 811 812 func (b *BreakNode) Type() NodeType { 813 return b.NodeType 814 } 815 816 func (b *BreakNode) String() string { 817 return "{{break}}" 818 } 819 820 func (b *BreakNode) Copy() Node { 821 return b.tr.newBreak(b.Pos) 822 } 823 824 func (b *BreakNode) Position() Pos { 825 return b.Pos 826 } 827 828 func (b *BreakNode) tree() *Tree { 829 return b.tr 830 } 831 832 // ContinueNode represents a {{continue}} action. 833 type ContinueNode struct { 834 NodeType 835 Pos 836 tr *Tree 837 } 838 839 func (t *Tree) newContinue(pos Pos) *ContinueNode { 840 return &ContinueNode{NodeType: NodeContinue, Pos: pos, tr: t} 841 } 842 843 func (c *ContinueNode) Type() NodeType { 844 return c.NodeType 845 } 846 847 func (c *ContinueNode) String() string { 848 return "{{continue}}" 849 } 850 851 func (c *ContinueNode) Copy() Node { 852 return c.tr.newContinue(c.Pos) 853 } 854 855 func (c *ContinueNode) Position() Pos { 856 return c.Pos 857 } 858 859 func (c *ContinueNode) tree() *Tree { 860 return c.tr 861 } 862 863 // WithNode represents a {{with}} action and its commands. 864 type WithNode struct { 865 BranchNode 866 } 867 868 func (t *Tree) newWith(pos Pos, line int, pipe *PipeNode, list, elseList *ListNode) *WithNode { 869 return &WithNode{BranchNode{tr: t, NodeType: NodeWith, Pos: pos, Line: line, Pipe: pipe, List: list, ElseList: elseList}} 870 } 871 872 func (w *WithNode) Copy() Node { 873 return w.tr.newWith(w.Pos, w.Line, w.Pipe.CopyPipe(), w.List.CopyList(), w.ElseList.CopyList()) 874 } 875 876 // TemplateNode represents a {{template}} action. 877 type TemplateNode struct { 878 NodeType 879 Pos 880 tr *Tree 881 Line int // The line number in the input. Deprecated: Kept for compatibility. 882 Name string // The name of the template (unquoted). 883 Pipe *PipeNode // The command to evaluate as dot for the template. 884 } 885 886 func (t *Tree) newTemplate(pos Pos, line int, name string, pipe *PipeNode) *TemplateNode { 887 return &TemplateNode{tr: t, NodeType: NodeTemplate, Pos: pos, Line: line, Name: name, Pipe: pipe} 888 } 889 890 func (t *TemplateNode) String() string { 891 if t.Pipe == nil { 892 return fmt.Sprintf("{{template %q}}", t.Name) 893 } 894 return fmt.Sprintf("{{template %q %s}}", t.Name, t.Pipe) 895 } 896 897 func (t *TemplateNode) tree() *Tree { 898 return t.tr 899 } 900 901 func (t *TemplateNode) Copy() Node { 902 return t.tr.newTemplate(t.Pos, t.Line, t.Name, t.Pipe.CopyPipe()) 903 }