...

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  	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  }
	 973  

View as plain text