...

Source file src/text/template/parse/node.go

     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	)
    73	
    74	// Nodes.
    75	
    76	// ListNode holds a sequence of nodes.
    77	type ListNode struct {
    78		NodeType
    79		Pos
    80		tr    *Tree
    81		Nodes []Node // The element nodes in lexical order.
    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	// TextNode holds plain text.
   120	type TextNode struct {
   121		NodeType
   122		Pos
   123		tr   *Tree
   124		Text []byte // The text; may span newlines.
   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	// PipeNode holds a pipeline with optional declaration
   144	type PipeNode struct {
   145		NodeType
   146		Pos
   147		tr       *Tree
   148		Line     int             // The line number in the input. Deprecated: Kept for compatibility.
   149		IsAssign bool            // The variables are being assigned, not declared.
   150		Decl     []*VariableNode // Variables in lexical order.
   151		Cmds     []*CommandNode  // The commands in lexical order.
   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	// 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	// AssignNode 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, ".eEpP") {
   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	// WithNode represents a {{with}} action and its commands.
   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	// TemplateNode represents a {{template}} action.
   815	type TemplateNode struct {
   816		NodeType
   817		Pos
   818		tr   *Tree
   819		Line int       // The line number in the input. Deprecated: Kept for compatibility.
   820		Name string    // The name of the template (unquoted).
   821		Pipe *PipeNode // The command to evaluate as dot for the template.
   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