github.com/xushiwei/go@v0.0.0-20130601165731-2b9d83f45bc9/src/pkg/text/template/parse/parse.go (about)

     1  // Copyright 2011 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  // Package parse builds parse trees for templates as defined by text/template
     6  // and html/template. Clients should use those packages to construct templates
     7  // rather than this one, which provides shared internal data structures not
     8  // intended for general use.
     9  package parse
    10  
    11  import (
    12  	"bytes"
    13  	"fmt"
    14  	"runtime"
    15  	"strconv"
    16  	"strings"
    17  	"unicode"
    18  )
    19  
    20  // Tree is the representation of a single parsed template.
    21  type Tree struct {
    22  	Name      string    // name of the template represented by the tree.
    23  	ParseName string    // name of the top-level template during parsing, for error messages.
    24  	Root      *ListNode // top-level root of the tree.
    25  	text      string    // text parsed to create the template (or its parent)
    26  	// Parsing only; cleared after parse.
    27  	funcs     []map[string]interface{}
    28  	lex       *lexer
    29  	token     [3]item // three-token lookahead for parser.
    30  	peekCount int
    31  	vars      []string // variables defined at the moment.
    32  }
    33  
    34  // Parse returns a map from template name to parse.Tree, created by parsing the
    35  // templates described in the argument string. The top-level template will be
    36  // given the specified name. If an error is encountered, parsing stops and an
    37  // empty map is returned with the error.
    38  func Parse(name, text, leftDelim, rightDelim string, funcs ...map[string]interface{}) (treeSet map[string]*Tree, err error) {
    39  	treeSet = make(map[string]*Tree)
    40  	t := New(name)
    41  	t.text = text
    42  	_, err = t.Parse(text, leftDelim, rightDelim, treeSet, funcs...)
    43  	return
    44  }
    45  
    46  // next returns the next token.
    47  func (t *Tree) next() item {
    48  	if t.peekCount > 0 {
    49  		t.peekCount--
    50  	} else {
    51  		t.token[0] = t.lex.nextItem()
    52  	}
    53  	return t.token[t.peekCount]
    54  }
    55  
    56  // backup backs the input stream up one token.
    57  func (t *Tree) backup() {
    58  	t.peekCount++
    59  }
    60  
    61  // backup2 backs the input stream up two tokens.
    62  // The zeroth token is already there.
    63  func (t *Tree) backup2(t1 item) {
    64  	t.token[1] = t1
    65  	t.peekCount = 2
    66  }
    67  
    68  // backup3 backs the input stream up three tokens
    69  // The zeroth token is already there.
    70  func (t *Tree) backup3(t2, t1 item) { // Reverse order: we're pushing back.
    71  	t.token[1] = t1
    72  	t.token[2] = t2
    73  	t.peekCount = 3
    74  }
    75  
    76  // peek returns but does not consume the next token.
    77  func (t *Tree) peek() item {
    78  	if t.peekCount > 0 {
    79  		return t.token[t.peekCount-1]
    80  	}
    81  	t.peekCount = 1
    82  	t.token[0] = t.lex.nextItem()
    83  	return t.token[0]
    84  }
    85  
    86  // nextNonSpace returns the next non-space token.
    87  func (t *Tree) nextNonSpace() (token item) {
    88  	for {
    89  		token = t.next()
    90  		if token.typ != itemSpace {
    91  			break
    92  		}
    93  	}
    94  	return token
    95  }
    96  
    97  // peekNonSpace returns but does not consume the next non-space token.
    98  func (t *Tree) peekNonSpace() (token item) {
    99  	for {
   100  		token = t.next()
   101  		if token.typ != itemSpace {
   102  			break
   103  		}
   104  	}
   105  	t.backup()
   106  	return token
   107  }
   108  
   109  // Parsing.
   110  
   111  // New allocates a new parse tree with the given name.
   112  func New(name string, funcs ...map[string]interface{}) *Tree {
   113  	return &Tree{
   114  		Name:  name,
   115  		funcs: funcs,
   116  	}
   117  }
   118  
   119  // ErrorContext returns a textual representation of the location of the node in the input text.
   120  func (t *Tree) ErrorContext(n Node) (location, context string) {
   121  	pos := int(n.Position())
   122  	text := t.text[:pos]
   123  	byteNum := strings.LastIndex(text, "\n")
   124  	if byteNum == -1 {
   125  		byteNum = pos // On first line.
   126  	} else {
   127  		byteNum++ // After the newline.
   128  		byteNum = pos - byteNum
   129  	}
   130  	lineNum := 1 + strings.Count(text, "\n")
   131  	context = n.String()
   132  	if len(context) > 20 {
   133  		context = fmt.Sprintf("%.20s...", context)
   134  	}
   135  	return fmt.Sprintf("%s:%d:%d", t.ParseName, lineNum, byteNum), context
   136  }
   137  
   138  // errorf formats the error and terminates processing.
   139  func (t *Tree) errorf(format string, args ...interface{}) {
   140  	t.Root = nil
   141  	format = fmt.Sprintf("template: %s:%d: %s", t.ParseName, t.lex.lineNumber(), format)
   142  	panic(fmt.Errorf(format, args...))
   143  }
   144  
   145  // error terminates processing.
   146  func (t *Tree) error(err error) {
   147  	t.errorf("%s", err)
   148  }
   149  
   150  // expect consumes the next token and guarantees it has the required type.
   151  func (t *Tree) expect(expected itemType, context string) item {
   152  	token := t.nextNonSpace()
   153  	if token.typ != expected {
   154  		t.unexpected(token, context)
   155  	}
   156  	return token
   157  }
   158  
   159  // expectOneOf consumes the next token and guarantees it has one of the required types.
   160  func (t *Tree) expectOneOf(expected1, expected2 itemType, context string) item {
   161  	token := t.nextNonSpace()
   162  	if token.typ != expected1 && token.typ != expected2 {
   163  		t.unexpected(token, context)
   164  	}
   165  	return token
   166  }
   167  
   168  // unexpected complains about the token and terminates processing.
   169  func (t *Tree) unexpected(token item, context string) {
   170  	t.errorf("unexpected %s in %s", token, context)
   171  }
   172  
   173  // recover is the handler that turns panics into returns from the top level of Parse.
   174  func (t *Tree) recover(errp *error) {
   175  	e := recover()
   176  	if e != nil {
   177  		if _, ok := e.(runtime.Error); ok {
   178  			panic(e)
   179  		}
   180  		if t != nil {
   181  			t.stopParse()
   182  		}
   183  		*errp = e.(error)
   184  	}
   185  	return
   186  }
   187  
   188  // startParse initializes the parser, using the lexer.
   189  func (t *Tree) startParse(funcs []map[string]interface{}, lex *lexer) {
   190  	t.Root = nil
   191  	t.lex = lex
   192  	t.vars = []string{"$"}
   193  	t.funcs = funcs
   194  }
   195  
   196  // stopParse terminates parsing.
   197  func (t *Tree) stopParse() {
   198  	t.lex = nil
   199  	t.vars = nil
   200  	t.funcs = nil
   201  }
   202  
   203  // atEOF returns true if, possibly after spaces, we're at EOF.
   204  func (t *Tree) atEOF() bool {
   205  	for {
   206  		token := t.peek()
   207  		switch token.typ {
   208  		case itemEOF:
   209  			return true
   210  		case itemText:
   211  			for _, r := range token.val {
   212  				if !unicode.IsSpace(r) {
   213  					return false
   214  				}
   215  			}
   216  			t.next() // skip spaces.
   217  			continue
   218  		}
   219  		break
   220  	}
   221  	return false
   222  }
   223  
   224  // Parse parses the template definition string to construct a representation of
   225  // the template for execution. If either action delimiter string is empty, the
   226  // default ("{{" or "}}") is used. Embedded template definitions are added to
   227  // the treeSet map.
   228  func (t *Tree) Parse(text, leftDelim, rightDelim string, treeSet map[string]*Tree, funcs ...map[string]interface{}) (tree *Tree, err error) {
   229  	defer t.recover(&err)
   230  	t.ParseName = t.Name
   231  	t.startParse(funcs, lex(t.Name, text, leftDelim, rightDelim))
   232  	t.text = text
   233  	t.parse(treeSet)
   234  	t.add(treeSet)
   235  	t.stopParse()
   236  	return t, nil
   237  }
   238  
   239  // add adds tree to the treeSet.
   240  func (t *Tree) add(treeSet map[string]*Tree) {
   241  	tree := treeSet[t.Name]
   242  	if tree == nil || IsEmptyTree(tree.Root) {
   243  		treeSet[t.Name] = t
   244  		return
   245  	}
   246  	if !IsEmptyTree(t.Root) {
   247  		t.errorf("template: multiple definition of template %q", t.Name)
   248  	}
   249  }
   250  
   251  // IsEmptyTree reports whether this tree (node) is empty of everything but space.
   252  func IsEmptyTree(n Node) bool {
   253  	switch n := n.(type) {
   254  	case nil:
   255  		return true
   256  	case *ActionNode:
   257  	case *IfNode:
   258  	case *ListNode:
   259  		for _, node := range n.Nodes {
   260  			if !IsEmptyTree(node) {
   261  				return false
   262  			}
   263  		}
   264  		return true
   265  	case *RangeNode:
   266  	case *TemplateNode:
   267  	case *TextNode:
   268  		return len(bytes.TrimSpace(n.Text)) == 0
   269  	case *WithNode:
   270  	default:
   271  		panic("unknown node: " + n.String())
   272  	}
   273  	return false
   274  }
   275  
   276  // parse is the top-level parser for a template, essentially the same
   277  // as itemList except it also parses {{define}} actions.
   278  // It runs to EOF.
   279  func (t *Tree) parse(treeSet map[string]*Tree) (next Node) {
   280  	t.Root = newList(t.peek().pos)
   281  	for t.peek().typ != itemEOF {
   282  		if t.peek().typ == itemLeftDelim {
   283  			delim := t.next()
   284  			if t.nextNonSpace().typ == itemDefine {
   285  				newT := New("definition") // name will be updated once we know it.
   286  				newT.text = t.text
   287  				newT.ParseName = t.ParseName
   288  				newT.startParse(t.funcs, t.lex)
   289  				newT.parseDefinition(treeSet)
   290  				continue
   291  			}
   292  			t.backup2(delim)
   293  		}
   294  		n := t.textOrAction()
   295  		if n.Type() == nodeEnd {
   296  			t.errorf("unexpected %s", n)
   297  		}
   298  		t.Root.append(n)
   299  	}
   300  	return nil
   301  }
   302  
   303  // parseDefinition parses a {{define}} ...  {{end}} template definition and
   304  // installs the definition in the treeSet map.  The "define" keyword has already
   305  // been scanned.
   306  func (t *Tree) parseDefinition(treeSet map[string]*Tree) {
   307  	const context = "define clause"
   308  	name := t.expectOneOf(itemString, itemRawString, context)
   309  	var err error
   310  	t.Name, err = strconv.Unquote(name.val)
   311  	if err != nil {
   312  		t.error(err)
   313  	}
   314  	t.expect(itemRightDelim, context)
   315  	var end Node
   316  	t.Root, end = t.itemList()
   317  	if end.Type() != nodeEnd {
   318  		t.errorf("unexpected %s in %s", end, context)
   319  	}
   320  	t.add(treeSet)
   321  	t.stopParse()
   322  }
   323  
   324  // itemList:
   325  //	textOrAction*
   326  // Terminates at {{end}} or {{else}}, returned separately.
   327  func (t *Tree) itemList() (list *ListNode, next Node) {
   328  	list = newList(t.peekNonSpace().pos)
   329  	for t.peekNonSpace().typ != itemEOF {
   330  		n := t.textOrAction()
   331  		switch n.Type() {
   332  		case nodeEnd, nodeElse:
   333  			return list, n
   334  		}
   335  		list.append(n)
   336  	}
   337  	t.errorf("unexpected EOF")
   338  	return
   339  }
   340  
   341  // textOrAction:
   342  //	text | action
   343  func (t *Tree) textOrAction() Node {
   344  	switch token := t.nextNonSpace(); token.typ {
   345  	case itemText:
   346  		return newText(token.pos, token.val)
   347  	case itemLeftDelim:
   348  		return t.action()
   349  	default:
   350  		t.unexpected(token, "input")
   351  	}
   352  	return nil
   353  }
   354  
   355  // Action:
   356  //	control
   357  //	command ("|" command)*
   358  // Left delim is past. Now get actions.
   359  // First word could be a keyword such as range.
   360  func (t *Tree) action() (n Node) {
   361  	switch token := t.nextNonSpace(); token.typ {
   362  	case itemElse:
   363  		return t.elseControl()
   364  	case itemEnd:
   365  		return t.endControl()
   366  	case itemIf:
   367  		return t.ifControl()
   368  	case itemRange:
   369  		return t.rangeControl()
   370  	case itemTemplate:
   371  		return t.templateControl()
   372  	case itemWith:
   373  		return t.withControl()
   374  	}
   375  	t.backup()
   376  	// Do not pop variables; they persist until "end".
   377  	return newAction(t.peek().pos, t.lex.lineNumber(), t.pipeline("command"))
   378  }
   379  
   380  // Pipeline:
   381  //	declarations? command ('|' command)*
   382  func (t *Tree) pipeline(context string) (pipe *PipeNode) {
   383  	var decl []*VariableNode
   384  	pos := t.peekNonSpace().pos
   385  	// Are there declarations?
   386  	for {
   387  		if v := t.peekNonSpace(); v.typ == itemVariable {
   388  			t.next()
   389  			// Since space is a token, we need 3-token look-ahead here in the worst case:
   390  			// in "$x foo" we need to read "foo" (as opposed to ":=") to know that $x is an
   391  			// argument variable rather than a declaration. So remember the token
   392  			// adjacent to the variable so we can push it back if necessary.
   393  			tokenAfterVariable := t.peek()
   394  			if next := t.peekNonSpace(); next.typ == itemColonEquals || (next.typ == itemChar && next.val == ",") {
   395  				t.nextNonSpace()
   396  				variable := newVariable(v.pos, v.val)
   397  				decl = append(decl, variable)
   398  				t.vars = append(t.vars, v.val)
   399  				if next.typ == itemChar && next.val == "," {
   400  					if context == "range" && len(decl) < 2 {
   401  						continue
   402  					}
   403  					t.errorf("too many declarations in %s", context)
   404  				}
   405  			} else if tokenAfterVariable.typ == itemSpace {
   406  				t.backup3(v, tokenAfterVariable)
   407  			} else {
   408  				t.backup2(v)
   409  			}
   410  		}
   411  		break
   412  	}
   413  	pipe = newPipeline(pos, t.lex.lineNumber(), decl)
   414  	for {
   415  		switch token := t.nextNonSpace(); token.typ {
   416  		case itemRightDelim, itemRightParen:
   417  			if len(pipe.Cmds) == 0 {
   418  				t.errorf("missing value for %s", context)
   419  			}
   420  			if token.typ == itemRightParen {
   421  				t.backup()
   422  			}
   423  			return
   424  		case itemBool, itemCharConstant, itemComplex, itemDot, itemField, itemIdentifier,
   425  			itemNumber, itemNil, itemRawString, itemString, itemVariable, itemLeftParen:
   426  			t.backup()
   427  			pipe.append(t.command())
   428  		default:
   429  			t.unexpected(token, context)
   430  		}
   431  	}
   432  }
   433  
   434  func (t *Tree) parseControl(context string) (pos Pos, line int, pipe *PipeNode, list, elseList *ListNode) {
   435  	defer t.popVars(len(t.vars))
   436  	line = t.lex.lineNumber()
   437  	pipe = t.pipeline(context)
   438  	var next Node
   439  	list, next = t.itemList()
   440  	switch next.Type() {
   441  	case nodeEnd: //done
   442  	case nodeElse:
   443  		elseList, next = t.itemList()
   444  		if next.Type() != nodeEnd {
   445  			t.errorf("expected end; found %s", next)
   446  		}
   447  	}
   448  	return pipe.Position(), line, pipe, list, elseList
   449  }
   450  
   451  // If:
   452  //	{{if pipeline}} itemList {{end}}
   453  //	{{if pipeline}} itemList {{else}} itemList {{end}}
   454  // If keyword is past.
   455  func (t *Tree) ifControl() Node {
   456  	return newIf(t.parseControl("if"))
   457  }
   458  
   459  // Range:
   460  //	{{range pipeline}} itemList {{end}}
   461  //	{{range pipeline}} itemList {{else}} itemList {{end}}
   462  // Range keyword is past.
   463  func (t *Tree) rangeControl() Node {
   464  	return newRange(t.parseControl("range"))
   465  }
   466  
   467  // With:
   468  //	{{with pipeline}} itemList {{end}}
   469  //	{{with pipeline}} itemList {{else}} itemList {{end}}
   470  // If keyword is past.
   471  func (t *Tree) withControl() Node {
   472  	return newWith(t.parseControl("with"))
   473  }
   474  
   475  // End:
   476  //	{{end}}
   477  // End keyword is past.
   478  func (t *Tree) endControl() Node {
   479  	return newEnd(t.expect(itemRightDelim, "end").pos)
   480  }
   481  
   482  // Else:
   483  //	{{else}}
   484  // Else keyword is past.
   485  func (t *Tree) elseControl() Node {
   486  	return newElse(t.expect(itemRightDelim, "else").pos, t.lex.lineNumber())
   487  }
   488  
   489  // Template:
   490  //	{{template stringValue pipeline}}
   491  // Template keyword is past.  The name must be something that can evaluate
   492  // to a string.
   493  func (t *Tree) templateControl() Node {
   494  	var name string
   495  	token := t.nextNonSpace()
   496  	switch token.typ {
   497  	case itemString, itemRawString:
   498  		s, err := strconv.Unquote(token.val)
   499  		if err != nil {
   500  			t.error(err)
   501  		}
   502  		name = s
   503  	default:
   504  		t.unexpected(token, "template invocation")
   505  	}
   506  	var pipe *PipeNode
   507  	if t.nextNonSpace().typ != itemRightDelim {
   508  		t.backup()
   509  		// Do not pop variables; they persist until "end".
   510  		pipe = t.pipeline("template")
   511  	}
   512  	return newTemplate(token.pos, t.lex.lineNumber(), name, pipe)
   513  }
   514  
   515  // command:
   516  //	operand (space operand)*
   517  // space-separated arguments up to a pipeline character or right delimiter.
   518  // we consume the pipe character but leave the right delim to terminate the action.
   519  func (t *Tree) command() *CommandNode {
   520  	cmd := newCommand(t.peekNonSpace().pos)
   521  	for {
   522  		t.peekNonSpace() // skip leading spaces.
   523  		operand := t.operand()
   524  		if operand != nil {
   525  			cmd.append(operand)
   526  		}
   527  		switch token := t.next(); token.typ {
   528  		case itemSpace:
   529  			continue
   530  		case itemError:
   531  			t.errorf("%s", token.val)
   532  		case itemRightDelim, itemRightParen:
   533  			t.backup()
   534  		case itemPipe:
   535  		default:
   536  			t.errorf("unexpected %s in operand; missing space?", token)
   537  		}
   538  		break
   539  	}
   540  	if len(cmd.Args) == 0 {
   541  		t.errorf("empty command")
   542  	}
   543  	return cmd
   544  }
   545  
   546  // operand:
   547  //	term .Field*
   548  // An operand is a space-separated component of a command,
   549  // a term possibly followed by field accesses.
   550  // A nil return means the next item is not an operand.
   551  func (t *Tree) operand() Node {
   552  	node := t.term()
   553  	if node == nil {
   554  		return nil
   555  	}
   556  	if t.peek().typ == itemField {
   557  		chain := newChain(t.peek().pos, node)
   558  		for t.peek().typ == itemField {
   559  			chain.Add(t.next().val)
   560  		}
   561  		// Compatibility with original API: If the term is of type NodeField
   562  		// or NodeVariable, just put more fields on the original.
   563  		// Otherwise, keep the Chain node.
   564  		// TODO: Switch to Chains always when we can.
   565  		switch node.Type() {
   566  		case NodeField:
   567  			node = newField(chain.Position(), chain.String())
   568  		case NodeVariable:
   569  			node = newVariable(chain.Position(), chain.String())
   570  		default:
   571  			node = chain
   572  		}
   573  	}
   574  	return node
   575  }
   576  
   577  // term:
   578  //	literal (number, string, nil, boolean)
   579  //	function (identifier)
   580  //	.
   581  //	.Field
   582  //	$
   583  //	'(' pipeline ')'
   584  // A term is a simple "expression".
   585  // A nil return means the next item is not a term.
   586  func (t *Tree) term() Node {
   587  	switch token := t.nextNonSpace(); token.typ {
   588  	case itemError:
   589  		t.errorf("%s", token.val)
   590  	case itemIdentifier:
   591  		if !t.hasFunction(token.val) {
   592  			t.errorf("function %q not defined", token.val)
   593  		}
   594  		return NewIdentifier(token.val).SetPos(token.pos)
   595  	case itemDot:
   596  		return newDot(token.pos)
   597  	case itemNil:
   598  		return newNil(token.pos)
   599  	case itemVariable:
   600  		return t.useVar(token.pos, token.val)
   601  	case itemField:
   602  		return newField(token.pos, token.val)
   603  	case itemBool:
   604  		return newBool(token.pos, token.val == "true")
   605  	case itemCharConstant, itemComplex, itemNumber:
   606  		number, err := newNumber(token.pos, token.val, token.typ)
   607  		if err != nil {
   608  			t.error(err)
   609  		}
   610  		return number
   611  	case itemLeftParen:
   612  		pipe := t.pipeline("parenthesized pipeline")
   613  		if token := t.next(); token.typ != itemRightParen {
   614  			t.errorf("unclosed right paren: unexpected %s", token)
   615  		}
   616  		return pipe
   617  	case itemString, itemRawString:
   618  		s, err := strconv.Unquote(token.val)
   619  		if err != nil {
   620  			t.error(err)
   621  		}
   622  		return newString(token.pos, token.val, s)
   623  	}
   624  	t.backup()
   625  	return nil
   626  }
   627  
   628  // hasFunction reports if a function name exists in the Tree's maps.
   629  func (t *Tree) hasFunction(name string) bool {
   630  	for _, funcMap := range t.funcs {
   631  		if funcMap == nil {
   632  			continue
   633  		}
   634  		if funcMap[name] != nil {
   635  			return true
   636  		}
   637  	}
   638  	return false
   639  }
   640  
   641  // popVars trims the variable list to the specified length
   642  func (t *Tree) popVars(n int) {
   643  	t.vars = t.vars[:n]
   644  }
   645  
   646  // useVar returns a node for a variable reference. It errors if the
   647  // variable is not defined.
   648  func (t *Tree) useVar(pos Pos, name string) Node {
   649  	v := newVariable(pos, name)
   650  	for _, varName := range t.vars {
   651  		if varName == v.Ident[0] {
   652  			return v
   653  		}
   654  	}
   655  	t.errorf("undefined variable %q", v.Ident[0])
   656  	return nil
   657  }