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

Documentation: text/template/parse

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

View as plain text