src/pkg/text/template/parse/node.go - The Go Programming Language

Golang

Source file src/pkg/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	// A node is an element in the parse tree. The interface is trivial.
    17	type Node interface {
    18		Type() NodeType
    19		String() string
    20		// Copy does a deep copy of the Node and all its components.
    21		// To avoid type assertions, some XxxNodes also have specialized
    22		// CopyXxx methods that return *XxxNode.
    23		Copy() Node
    24	}
    25	
    26	// NodeType identifies the type of a parse tree node.
    27	type NodeType int
    28	
    29	// Type returns itself and provides an easy default implementation
    30	// for embedding in a Node. Embedded in all non-trivial Nodes.
    31	func (t NodeType) Type() NodeType {
    32		return t
    33	}
    34	
    35	const (
    36		NodeText       NodeType = iota // Plain text.
    37		NodeAction                     // A simple action such as field evaluation.
    38		NodeBool                       // A boolean constant.
    39		NodeCommand                    // An element of a pipeline.
    40		NodeDot                        // The cursor, dot.
    41		nodeElse                       // An else action. Not added to tree.
    42		nodeEnd                        // An end action. Not added to tree.
    43		NodeField                      // A field or method name.
    44		NodeIdentifier                 // An identifier; always a function name.
    45		NodeIf                         // An if action.
    46		NodeList                       // A list of Nodes.
    47		NodeNumber                     // A numerical constant.
    48		NodePipe                       // A pipeline of commands.
    49		NodeRange                      // A range action.
    50		NodeString                     // A string constant.
    51		NodeTemplate                   // A template invocation action.
    52		NodeVariable                   // A $ variable.
    53		NodeWith                       // A with action.
    54	)
    55	
    56	// Nodes.
    57	
    58	// ListNode holds a sequence of nodes.
    59	type ListNode struct {
    60		NodeType
    61		Nodes []Node // The element nodes in lexical order.
    62	}
    63	
    64	func newList() *ListNode {
    65		return &ListNode{NodeType: NodeList}
    66	}
    67	
    68	func (l *ListNode) append(n Node) {
    69		l.Nodes = append(l.Nodes, n)
    70	}
    71	
    72	func (l *ListNode) String() string {
    73		b := new(bytes.Buffer)
    74		for _, n := range l.Nodes {
    75			fmt.Fprint(b, n)
    76		}
    77		return b.String()
    78	}
    79	
    80	func (l *ListNode) CopyList() *ListNode {
    81		if l == nil {
    82			return l
    83		}
    84		n := newList()
    85		for _, elem := range l.Nodes {
    86			n.append(elem.Copy())
    87		}
    88		return n
    89	}
    90	
    91	func (l *ListNode) Copy() Node {
    92		return l.CopyList()
    93	}
    94	
    95	// TextNode holds plain text.
    96	type TextNode struct {
    97		NodeType
    98		Text []byte // The text; may span newlines.
    99	}
   100	
   101	func newText(text string) *TextNode {
   102		return &TextNode{NodeType: NodeText, Text: []byte(text)}
   103	}
   104	
   105	func (t *TextNode) String() string {
   106		return fmt.Sprintf("%q", t.Text)
   107	}
   108	
   109	func (t *TextNode) Copy() Node {
   110		return &TextNode{NodeType: NodeText, Text: append([]byte{}, t.Text...)}
   111	}
   112	
   113	// PipeNode holds a pipeline with optional declaration
   114	type PipeNode struct {
   115		NodeType
   116		Line int             // The line number in the input.
   117		Decl []*VariableNode // Variable declarations in lexical order.
   118		Cmds []*CommandNode  // The commands in lexical order.
   119	}
   120	
   121	func newPipeline(line int, decl []*VariableNode) *PipeNode {
   122		return &PipeNode{NodeType: NodePipe, Line: line, Decl: decl}
   123	}
   124	
   125	func (p *PipeNode) append(command *CommandNode) {
   126		p.Cmds = append(p.Cmds, command)
   127	}
   128	
   129	func (p *PipeNode) String() string {
   130		s := ""
   131		if len(p.Decl) > 0 {
   132			for i, v := range p.Decl {
   133				if i > 0 {
   134					s += ", "
   135				}
   136				s += v.String()
   137			}
   138			s += " := "
   139		}
   140		for i, c := range p.Cmds {
   141			if i > 0 {
   142				s += " | "
   143			}
   144			s += c.String()
   145		}
   146		return s
   147	}
   148	
   149	func (p *PipeNode) CopyPipe() *PipeNode {
   150		if p == nil {
   151			return p
   152		}
   153		var decl []*VariableNode
   154		for _, d := range p.Decl {
   155			decl = append(decl, d.Copy().(*VariableNode))
   156		}
   157		n := newPipeline(p.Line, decl)
   158		for _, c := range p.Cmds {
   159			n.append(c.Copy().(*CommandNode))
   160		}
   161		return n
   162	}
   163	
   164	func (p *PipeNode) Copy() Node {
   165		return p.CopyPipe()
   166	}
   167	
   168	// ActionNode holds an action (something bounded by delimiters).
   169	// Control actions have their own nodes; ActionNode represents simple
   170	// ones such as field evaluations.
   171	type ActionNode struct {
   172		NodeType
   173		Line int       // The line number in the input.
   174		Pipe *PipeNode // The pipeline in the action.
   175	}
   176	
   177	func newAction(line int, pipe *PipeNode) *ActionNode {
   178		return &ActionNode{NodeType: NodeAction, Line: line, Pipe: pipe}
   179	}
   180	
   181	func (a *ActionNode) String() string {
   182		return fmt.Sprintf("{{%s}}", a.Pipe)
   183	
   184	}
   185	
   186	func (a *ActionNode) Copy() Node {
   187		return newAction(a.Line, a.Pipe.CopyPipe())
   188	
   189	}
   190	
   191	// CommandNode holds a command (a pipeline inside an evaluating action).
   192	type CommandNode struct {
   193		NodeType
   194		Args []Node // Arguments in lexical order: Identifier, field, or constant.
   195	}
   196	
   197	func newCommand() *CommandNode {
   198		return &CommandNode{NodeType: NodeCommand}
   199	}
   200	
   201	func (c *CommandNode) append(arg Node) {
   202		c.Args = append(c.Args, arg)
   203	}
   204	
   205	func (c *CommandNode) String() string {
   206		s := ""
   207		for i, arg := range c.Args {
   208			if i > 0 {
   209				s += " "
   210			}
   211			s += arg.String()
   212		}
   213		return s
   214	}
   215	
   216	func (c *CommandNode) Copy() Node {
   217		if c == nil {
   218			return c
   219		}
   220		n := newCommand()
   221		for _, c := range c.Args {
   222			n.append(c.Copy())
   223		}
   224		return n
   225	}
   226	
   227	// IdentifierNode holds an identifier.
   228	type IdentifierNode struct {
   229		NodeType
   230		Ident string // The identifier's name.
   231	}
   232	
   233	// NewIdentifier returns a new IdentifierNode with the given identifier name.
   234	func NewIdentifier(ident string) *IdentifierNode {
   235		return &IdentifierNode{NodeType: NodeIdentifier, Ident: ident}
   236	}
   237	
   238	func (i *IdentifierNode) String() string {
   239		return i.Ident
   240	}
   241	
   242	func (i *IdentifierNode) Copy() Node {
   243		return NewIdentifier(i.Ident)
   244	}
   245	
   246	// VariableNode holds a list of variable names. The dollar sign is
   247	// part of the name.
   248	type VariableNode struct {
   249		NodeType
   250		Ident []string // Variable names in lexical order.
   251	}
   252	
   253	func newVariable(ident string) *VariableNode {
   254		return &VariableNode{NodeType: NodeVariable, Ident: strings.Split(ident, ".")}
   255	}
   256	
   257	func (v *VariableNode) String() string {
   258		s := ""
   259		for i, id := range v.Ident {
   260			if i > 0 {
   261				s += "."
   262			}
   263			s += id
   264		}
   265		return s
   266	}
   267	
   268	func (v *VariableNode) Copy() Node {
   269		return &VariableNode{NodeType: NodeVariable, Ident: append([]string{}, v.Ident...)}
   270	}
   271	
   272	// DotNode holds the special identifier '.'. It is represented by a nil pointer.
   273	type DotNode bool
   274	
   275	func newDot() *DotNode {
   276		return nil
   277	}
   278	
   279	func (d *DotNode) Type() NodeType {
   280		return NodeDot
   281	}
   282	
   283	func (d *DotNode) String() string {
   284		return "."
   285	}
   286	
   287	func (d *DotNode) Copy() Node {
   288		return newDot()
   289	}
   290	
   291	// FieldNode holds a field (identifier starting with '.').
   292	// The names may be chained ('.x.y').
   293	// The period is dropped from each ident.
   294	type FieldNode struct {
   295		NodeType
   296		Ident []string // The identifiers in lexical order.
   297	}
   298	
   299	func newField(ident string) *FieldNode {
   300		return &FieldNode{NodeType: NodeField, Ident: strings.Split(ident[1:], ".")} // [1:] to drop leading period
   301	}
   302	
   303	func (f *FieldNode) String() string {
   304		s := ""
   305		for _, id := range f.Ident {
   306			s += "." + id
   307		}
   308		return s
   309	}
   310	
   311	func (f *FieldNode) Copy() Node {
   312		return &FieldNode{NodeType: NodeField, Ident: append([]string{}, f.Ident...)}
   313	}
   314	
   315	// BoolNode holds a boolean constant.
   316	type BoolNode struct {
   317		NodeType
   318		True bool // The value of the boolean constant.
   319	}
   320	
   321	func newBool(true bool) *BoolNode {
   322		return &BoolNode{NodeType: NodeBool, True: true}
   323	}
   324	
   325	func (b *BoolNode) String() string {
   326		if b.True {
   327			return "true"
   328		}
   329		return "false"
   330	}
   331	
   332	func (b *BoolNode) Copy() Node {
   333		return newBool(b.True)
   334	}
   335	
   336	// NumberNode holds a number: signed or unsigned integer, float, or complex.
   337	// The value is parsed and stored under all the types that can represent the value.
   338	// This simulates in a small amount of code the behavior of Go's ideal constants.
   339	type NumberNode struct {
   340		NodeType
   341		IsInt      bool       // Number has an integral value.
   342		IsUint     bool       // Number has an unsigned integral value.
   343		IsFloat    bool       // Number has a floating-point value.
   344		IsComplex  bool       // Number is complex.
   345		Int64      int64      // The signed integer value.
   346		Uint64     uint64     // The unsigned integer value.
   347		Float64    float64    // The floating-point value.
   348		Complex128 complex128 // The complex value.
   349		Text       string     // The original textual representation from the input.
   350	}
   351	
   352	func newNumber(text string, typ itemType) (*NumberNode, error) {
   353		n := &NumberNode{NodeType: NodeNumber, Text: text}
   354		switch typ {
   355		case itemCharConstant:
   356			rune, _, tail, err := strconv.UnquoteChar(text[1:], text[0])
   357			if err != nil {
   358				return nil, err
   359			}
   360			if tail != "'" {
   361				return nil, fmt.Errorf("malformed character constant: %s", text)
   362			}
   363			n.Int64 = int64(rune)
   364			n.IsInt = true
   365			n.Uint64 = uint64(rune)
   366			n.IsUint = true
   367			n.Float64 = float64(rune) // odd but those are the rules.
   368			n.IsFloat = true
   369			return n, nil
   370		case itemComplex:
   371			// fmt.Sscan can parse the pair, so let it do the work.
   372			if _, err := fmt.Sscan(text, &n.Complex128); err != nil {
   373				return nil, err
   374			}
   375			n.IsComplex = true
   376			n.simplifyComplex()
   377			return n, nil
   378		}
   379		// Imaginary constants can only be complex unless they are zero.
   380		if len(text) > 0 && text[len(text)-1] == 'i' {
   381			f, err := strconv.ParseFloat(text[:len(text)-1], 64)
   382			if err == nil {
   383				n.IsComplex = true
   384				n.Complex128 = complex(0, f)
   385				n.simplifyComplex()
   386				return n, nil
   387			}
   388		}
   389		// Do integer test first so we get 0x123 etc.
   390		u, err := strconv.ParseUint(text, 0, 64) // will fail for -0; fixed below.
   391		if err == nil {
   392			n.IsUint = true
   393			n.Uint64 = u
   394		}
   395		i, err := strconv.ParseInt(text, 0, 64)
   396		if err == nil {
   397			n.IsInt = true
   398			n.Int64 = i
   399			if i == 0 {
   400				n.IsUint = true // in case of -0.
   401				n.Uint64 = u
   402			}
   403		}
   404		// If an integer extraction succeeded, promote the float.
   405		if n.IsInt {
   406			n.IsFloat = true
   407			n.Float64 = float64(n.Int64)
   408		} else if n.IsUint {
   409			n.IsFloat = true
   410			n.Float64 = float64(n.Uint64)
   411		} else {
   412			f, err := strconv.ParseFloat(text, 64)
   413			if err == nil {
   414				n.IsFloat = true
   415				n.Float64 = f
   416				// If a floating-point extraction succeeded, extract the int if needed.
   417				if !n.IsInt && float64(int64(f)) == f {
   418					n.IsInt = true
   419					n.Int64 = int64(f)
   420				}
   421				if !n.IsUint && float64(uint64(f)) == f {
   422					n.IsUint = true
   423					n.Uint64 = uint64(f)
   424				}
   425			}
   426		}
   427		if !n.IsInt && !n.IsUint && !n.IsFloat {
   428			return nil, fmt.Errorf("illegal number syntax: %q", text)
   429		}
   430		return n, nil
   431	}
   432	
   433	// simplifyComplex pulls out any other types that are represented by the complex number.
   434	// These all require that the imaginary part be zero.
   435	func (n *NumberNode) simplifyComplex() {
   436		n.IsFloat = imag(n.Complex128) == 0
   437		if n.IsFloat {
   438			n.Float64 = real(n.Complex128)
   439			n.IsInt = float64(int64(n.Float64)) == n.Float64
   440			if n.IsInt {
   441				n.Int64 = int64(n.Float64)
   442			}
   443			n.IsUint = float64(uint64(n.Float64)) == n.Float64
   444			if n.IsUint {
   445				n.Uint64 = uint64(n.Float64)
   446			}
   447		}
   448	}
   449	
   450	func (n *NumberNode) String() string {
   451		return n.Text
   452	}
   453	
   454	func (n *NumberNode) Copy() Node {
   455		nn := new(NumberNode)
   456		*nn = *n // Easy, fast, correct.
   457		return nn
   458	}
   459	
   460	// StringNode holds a string constant. The value has been "unquoted".
   461	type StringNode struct {
   462		NodeType
   463		Quoted string // The original text of the string, with quotes.
   464		Text   string // The string, after quote processing.
   465	}
   466	
   467	func newString(orig, text string) *StringNode {
   468		return &StringNode{NodeType: NodeString, Quoted: orig, Text: text}
   469	}
   470	
   471	func (s *StringNode) String() string {
   472		return s.Quoted
   473	}
   474	
   475	func (s *StringNode) Copy() Node {
   476		return newString(s.Quoted, s.Text)
   477	}
   478	
   479	// endNode represents an {{end}} action. It is represented by a nil pointer.
   480	// It does not appear in the final parse tree.
   481	type endNode bool
   482	
   483	func newEnd() *endNode {
   484		return nil
   485	}
   486	
   487	func (e *endNode) Type() NodeType {
   488		return nodeEnd
   489	}
   490	
   491	func (e *endNode) String() string {
   492		return "{{end}}"
   493	}
   494	
   495	func (e *endNode) Copy() Node {
   496		return newEnd()
   497	}
   498	
   499	// elseNode represents an {{else}} action. Does not appear in the final tree.
   500	type elseNode struct {
   501		NodeType
   502		Line int // The line number in the input.
   503	}
   504	
   505	func newElse(line int) *elseNode {
   506		return &elseNode{NodeType: nodeElse, Line: line}
   507	}
   508	
   509	func (e *elseNode) Type() NodeType {
   510		return nodeElse
   511	}
   512	
   513	func (e *elseNode) String() string {
   514		return "{{else}}"
   515	}
   516	
   517	func (e *elseNode) Copy() Node {
   518		return newElse(e.Line)
   519	}
   520	
   521	// BranchNode is the common representation of if, range, and with.
   522	type BranchNode struct {
   523		NodeType
   524		Line     int       // The line number in the input.
   525		Pipe     *PipeNode // The pipeline to be evaluated.
   526		List     *ListNode // What to execute if the value is non-empty.
   527		ElseList *ListNode // What to execute if the value is empty (nil if absent).
   528	}
   529	
   530	func (b *BranchNode) String() string {
   531		name := ""
   532		switch b.NodeType {
   533		case NodeIf:
   534			name = "if"
   535		case NodeRange:
   536			name = "range"
   537		case NodeWith:
   538			name = "with"
   539		default:
   540			panic("unknown branch type")
   541		}
   542		if b.ElseList != nil {
   543			return fmt.Sprintf("{{%s %s}}%s{{else}}%s{{end}}", name, b.Pipe, b.List, b.ElseList)
   544		}
   545		return fmt.Sprintf("{{%s %s}}%s{{end}}", name, b.Pipe, b.List)
   546	}
   547	
   548	// IfNode represents an {{if}} action and its commands.
   549	type IfNode struct {
   550		BranchNode
   551	}
   552	
   553	func newIf(line int, pipe *PipeNode, list, elseList *ListNode) *IfNode {
   554		return &IfNode{BranchNode{NodeType: NodeIf, Line: line, Pipe: pipe, List: list, ElseList: elseList}}
   555	}
   556	
   557	func (i *IfNode) Copy() Node {
   558		return newIf(i.Line, i.Pipe.CopyPipe(), i.List.CopyList(), i.ElseList.CopyList())
   559	}
   560	
   561	// RangeNode represents a {{range}} action and its commands.
   562	type RangeNode struct {
   563		BranchNode
   564	}
   565	
   566	func newRange(line int, pipe *PipeNode, list, elseList *ListNode) *RangeNode {
   567		return &RangeNode{BranchNode{NodeType: NodeRange, Line: line, Pipe: pipe, List: list, ElseList: elseList}}
   568	}
   569	
   570	func (r *RangeNode) Copy() Node {
   571		return newRange(r.Line, r.Pipe.CopyPipe(), r.List.CopyList(), r.ElseList.CopyList())
   572	}
   573	
   574	// WithNode represents a {{with}} action and its commands.
   575	type WithNode struct {
   576		BranchNode
   577	}
   578	
   579	func newWith(line int, pipe *PipeNode, list, elseList *ListNode) *WithNode {
   580		return &WithNode{BranchNode{NodeType: NodeWith, Line: line, Pipe: pipe, List: list, ElseList: elseList}}
   581	}
   582	
   583	func (w *WithNode) Copy() Node {
   584		return newWith(w.Line, w.Pipe.CopyPipe(), w.List.CopyList(), w.ElseList.CopyList())
   585	}
   586	
   587	// TemplateNode represents a {{template}} action.
   588	type TemplateNode struct {
   589		NodeType
   590		Line int       // The line number in the input.
   591		Name string    // The name of the template (unquoted).
   592		Pipe *PipeNode // The command to evaluate as dot for the template.
   593	}
   594	
   595	func newTemplate(line int, name string, pipe *PipeNode) *TemplateNode {
   596		return &TemplateNode{NodeType: NodeTemplate, Line: line, Name: name, Pipe: pipe}
   597	}
   598	
   599	func (t *TemplateNode) String() string {
   600		if t.Pipe == nil {
   601			return fmt.Sprintf("{{template %q}}", t.Name)
   602		}
   603		return fmt.Sprintf("{{template %q %s}}", t.Name, t.Pipe)
   604	}
   605	
   606	func (t *TemplateNode) Copy() Node {
   607		return newTemplate(t.Line, t.Name, t.Pipe.CopyPipe())
   608	}