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

Golang

Source file src/pkg/text/template/parse/parse.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	// 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		"unicode"
    17	)
    18	
    19	// Tree is the representation of a single parsed template.
    20	type Tree struct {
    21		Name string    // name of the template represented by the tree.
    22		Root *ListNode // top-level root of the tree.
    23		// Parsing only; cleared after parse.
    24		funcs     []map[string]interface{}
    25		lex       *lexer
    26		token     [2]item // two-token lookahead for parser.
    27		peekCount int
    28		vars      []string // variables defined at the moment.
    29	}
    30	
    31	// Parse returns a map from template name to parse.Tree, created by parsing the
    32	// templates described in the argument string. The top-level template will be
    33	// given the specified name. If an error is encountered, parsing stops and an
    34	// empty map is returned with the error.
    35	func Parse(name, text, leftDelim, rightDelim string, funcs ...map[string]interface{}) (treeSet map[string]*Tree, err error) {
    36		treeSet = make(map[string]*Tree)
    37		_, err = New(name).Parse(text, leftDelim, rightDelim, treeSet, funcs...)
    38		return
    39	}
    40	
    41	// next returns the next token.
    42	func (t *Tree) next() item {
    43		if t.peekCount > 0 {
    44			t.peekCount--
    45		} else {
    46			t.token[0] = t.lex.nextItem()
    47		}
    48		return t.token[t.peekCount]
    49	}
    50	
    51	// backup backs the input stream up one token.
    52	func (t *Tree) backup() {
    53		t.peekCount++
    54	}
    55	
    56	// backup2 backs the input stream up two tokens
    57	func (t *Tree) backup2(t1 item) {
    58		t.token[1] = t1
    59		t.peekCount = 2
    60	}
    61	
    62	// peek returns but does not consume the next token.
    63	func (t *Tree) peek() item {
    64		if t.peekCount > 0 {
    65			return t.token[t.peekCount-1]
    66		}
    67		t.peekCount = 1
    68		t.token[0] = t.lex.nextItem()
    69		return t.token[0]
    70	}
    71	
    72	// Parsing.
    73	
    74	// New allocates a new parse tree with the given name.
    75	func New(name string, funcs ...map[string]interface{}) *Tree {
    76		return &Tree{
    77			Name:  name,
    78			funcs: funcs,
    79		}
    80	}
    81	
    82	// errorf formats the error and terminates processing.
    83	func (t *Tree) errorf(format string, args ...interface{}) {
    84		t.Root = nil
    85		format = fmt.Sprintf("template: %s:%d: %s", t.Name, t.lex.lineNumber(), format)
    86		panic(fmt.Errorf(format, args...))
    87	}
    88	
    89	// error terminates processing.
    90	func (t *Tree) error(err error) {
    91		t.errorf("%s", err)
    92	}
    93	
    94	// expect consumes the next token and guarantees it has the required type.
    95	func (t *Tree) expect(expected itemType, context string) item {
    96		token := t.next()
    97		if token.typ != expected {
    98			t.errorf("expected %s in %s; got %s", expected, context, token)
    99		}
   100		return token
   101	}
   102	
   103	// expectEither consumes the next token and guarantees it has one of the required types.
   104	func (t *Tree) expectOneOf(expected1, expected2 itemType, context string) item {
   105		token := t.next()
   106		if token.typ != expected1 && token.typ != expected2 {
   107			t.errorf("expected %s or %s in %s; got %s", expected1, expected2, context, token)
   108		}
   109		return token
   110	}
   111	
   112	// unexpected complains about the token and terminates processing.
   113	func (t *Tree) unexpected(token item, context string) {
   114		t.errorf("unexpected %s in %s", token, context)
   115	}
   116	
   117	// recover is the handler that turns panics into returns from the top level of Parse.
   118	func (t *Tree) recover(errp *error) {
   119		e := recover()
   120		if e != nil {
   121			if _, ok := e.(runtime.Error); ok {
   122				panic(e)
   123			}
   124			if t != nil {
   125				t.stopParse()
   126			}
   127			*errp = e.(error)
   128		}
   129		return
   130	}
   131	
   132	// startParse initializes the parser, using the lexer.
   133	func (t *Tree) startParse(funcs []map[string]interface{}, lex *lexer) {
   134		t.Root = nil
   135		t.lex = lex
   136		t.vars = []string{"$"}
   137		t.funcs = funcs
   138	}
   139	
   140	// stopParse terminates parsing.
   141	func (t *Tree) stopParse() {
   142		t.lex = nil
   143		t.vars = nil
   144		t.funcs = nil
   145	}
   146	
   147	// atEOF returns true if, possibly after spaces, we're at EOF.
   148	func (t *Tree) atEOF() bool {
   149		for {
   150			token := t.peek()
   151			switch token.typ {
   152			case itemEOF:
   153				return true
   154			case itemText:
   155				for _, r := range token.val {
   156					if !unicode.IsSpace(r) {
   157						return false
   158					}
   159				}
   160				t.next() // skip spaces.
   161				continue
   162			}
   163			break
   164		}
   165		return false
   166	}
   167	
   168	// Parse parses the template definition string to construct a representation of
   169	// the template for execution. If either action delimiter string is empty, the
   170	// default ("{{" or "}}") is used. Embedded template definitions are added to
   171	// the treeSet map.
   172	func (t *Tree) Parse(s, leftDelim, rightDelim string, treeSet map[string]*Tree, funcs ...map[string]interface{}) (tree *Tree, err error) {
   173		defer t.recover(&err)
   174		t.startParse(funcs, lex(t.Name, s, leftDelim, rightDelim))
   175		t.parse(treeSet)
   176		t.add(treeSet)
   177		t.stopParse()
   178		return t, nil
   179	}
   180	
   181	// add adds tree to the treeSet.
   182	func (t *Tree) add(treeSet map[string]*Tree) {
   183		tree := treeSet[t.Name]
   184		if tree == nil || IsEmptyTree(tree.Root) {
   185			treeSet[t.Name] = t
   186			return
   187		}
   188		if !IsEmptyTree(t.Root) {
   189			t.errorf("template: multiple definition of template %q", t.Name)
   190		}
   191	}
   192	
   193	// IsEmptyTree reports whether this tree (node) is empty of everything but space.
   194	func IsEmptyTree(n Node) bool {
   195		switch n := n.(type) {
   196		case nil:
   197			return true
   198		case *ActionNode:
   199		case *IfNode:
   200		case *ListNode:
   201			for _, node := range n.Nodes {
   202				if !IsEmptyTree(node) {
   203					return false
   204				}
   205			}
   206			return true
   207		case *RangeNode:
   208		case *TemplateNode:
   209		case *TextNode:
   210			return len(bytes.TrimSpace(n.Text)) == 0
   211		case *WithNode:
   212		default:
   213			panic("unknown node: " + n.String())
   214		}
   215		return false
   216	}
   217	
   218	// parse is the top-level parser for a template, essentially the same
   219	// as itemList except it also parses {{define}} actions.
   220	// It runs to EOF.
   221	func (t *Tree) parse(treeSet map[string]*Tree) (next Node) {
   222		t.Root = newList()
   223		for t.peek().typ != itemEOF {
   224			if t.peek().typ == itemLeftDelim {
   225				delim := t.next()
   226				if t.next().typ == itemDefine {
   227					newT := New("definition") // name will be updated once we know it.
   228					newT.startParse(t.funcs, t.lex)
   229					newT.parseDefinition(treeSet)
   230					continue
   231				}
   232				t.backup2(delim)
   233			}
   234			n := t.textOrAction()
   235			if n.Type() == nodeEnd {
   236				t.errorf("unexpected %s", n)
   237			}
   238			t.Root.append(n)
   239		}
   240		return nil
   241	}
   242	
   243	// parseDefinition parses a {{define}} ...  {{end}} template definition and
   244	// installs the definition in the treeSet map.  The "define" keyword has already
   245	// been scanned.
   246	func (t *Tree) parseDefinition(treeSet map[string]*Tree) {
   247		const context = "define clause"
   248		name := t.expectOneOf(itemString, itemRawString, context)
   249		var err error
   250		t.Name, err = strconv.Unquote(name.val)
   251		if err != nil {
   252			t.error(err)
   253		}
   254		t.expect(itemRightDelim, context)
   255		var end Node
   256		t.Root, end = t.itemList()
   257		if end.Type() != nodeEnd {
   258			t.errorf("unexpected %s in %s", end, context)
   259		}
   260		t.stopParse()
   261		t.add(treeSet)
   262	}
   263	
   264	// itemList:
   265	//	textOrAction*
   266	// Terminates at {{end}} or {{else}}, returned separately.
   267	func (t *Tree) itemList() (list *ListNode, next Node) {
   268		list = newList()
   269		for t.peek().typ != itemEOF {
   270			n := t.textOrAction()
   271			switch n.Type() {
   272			case nodeEnd, nodeElse:
   273				return list, n
   274			}
   275			list.append(n)
   276		}
   277		t.errorf("unexpected EOF")
   278		return
   279	}
   280	
   281	// textOrAction:
   282	//	text | action
   283	func (t *Tree) textOrAction() Node {
   284		switch token := t.next(); token.typ {
   285		case itemText:
   286			return newText(token.val)
   287		case itemLeftDelim:
   288			return t.action()
   289		default:
   290			t.unexpected(token, "input")
   291		}
   292		return nil
   293	}
   294	
   295	// Action:
   296	//	control
   297	//	command ("|" command)*
   298	// Left delim is past. Now get actions.
   299	// First word could be a keyword such as range.
   300	func (t *Tree) action() (n Node) {
   301		switch token := t.next(); token.typ {
   302		case itemElse:
   303			return t.elseControl()
   304		case itemEnd:
   305			return t.endControl()
   306		case itemIf:
   307			return t.ifControl()
   308		case itemRange:
   309			return t.rangeControl()
   310		case itemTemplate:
   311			return t.templateControl()
   312		case itemWith:
   313			return t.withControl()
   314		}
   315		t.backup()
   316		// Do not pop variables; they persist until "end".
   317		return newAction(t.lex.lineNumber(), t.pipeline("command"))
   318	}
   319	
   320	// Pipeline:
   321	//	field or command
   322	//	pipeline "|" pipeline
   323	func (t *Tree) pipeline(context string) (pipe *PipeNode) {
   324		var decl []*VariableNode
   325		// Are there declarations?
   326		for {
   327			if v := t.peek(); v.typ == itemVariable {
   328				t.next()
   329				if next := t.peek(); next.typ == itemColonEquals || (next.typ == itemChar && next.val == ",") {
   330					t.next()
   331					variable := newVariable(v.val)
   332					if len(variable.Ident) != 1 {
   333						t.errorf("illegal variable in declaration: %s", v.val)
   334					}
   335					decl = append(decl, variable)
   336					t.vars = append(t.vars, v.val)
   337					if next.typ == itemChar && next.val == "," {
   338						if context == "range" && len(decl) < 2 {
   339							continue
   340						}
   341						t.errorf("too many declarations in %s", context)
   342					}
   343				} else {
   344					t.backup2(v)
   345				}
   346			}
   347			break
   348		}
   349		pipe = newPipeline(t.lex.lineNumber(), decl)
   350		for {
   351			switch token := t.next(); token.typ {
   352			case itemRightDelim:
   353				if len(pipe.Cmds) == 0 {
   354					t.errorf("missing value for %s", context)
   355				}
   356				return
   357			case itemBool, itemCharConstant, itemComplex, itemDot, itemField, itemIdentifier,
   358				itemVariable, itemNumber, itemRawString, itemString:
   359				t.backup()
   360				pipe.append(t.command())
   361			default:
   362				t.unexpected(token, context)
   363			}
   364		}
   365		return
   366	}
   367	
   368	func (t *Tree) parseControl(context string) (lineNum int, pipe *PipeNode, list, elseList *ListNode) {
   369		lineNum = t.lex.lineNumber()
   370		defer t.popVars(len(t.vars))
   371		pipe = t.pipeline(context)
   372		var next Node
   373		list, next = t.itemList()
   374		switch next.Type() {
   375		case nodeEnd: //done
   376		case nodeElse:
   377			elseList, next = t.itemList()
   378			if next.Type() != nodeEnd {
   379				t.errorf("expected end; found %s", next)
   380			}
   381			elseList = elseList
   382		}
   383		return lineNum, pipe, list, elseList
   384	}
   385	
   386	// If:
   387	//	{{if pipeline}} itemList {{end}}
   388	//	{{if pipeline}} itemList {{else}} itemList {{end}}
   389	// If keyword is past.
   390	func (t *Tree) ifControl() Node {
   391		return newIf(t.parseControl("if"))
   392	}
   393	
   394	// Range:
   395	//	{{range pipeline}} itemList {{end}}
   396	//	{{range pipeline}} itemList {{else}} itemList {{end}}
   397	// Range keyword is past.
   398	func (t *Tree) rangeControl() Node {
   399		return newRange(t.parseControl("range"))
   400	}
   401	
   402	// With:
   403	//	{{with pipeline}} itemList {{end}}
   404	//	{{with pipeline}} itemList {{else}} itemList {{end}}
   405	// If keyword is past.
   406	func (t *Tree) withControl() Node {
   407		return newWith(t.parseControl("with"))
   408	}
   409	
   410	// End:
   411	//	{{end}}
   412	// End keyword is past.
   413	func (t *Tree) endControl() Node {
   414		t.expect(itemRightDelim, "end")
   415		return newEnd()
   416	}
   417	
   418	// Else:
   419	//	{{else}}
   420	// Else keyword is past.
   421	func (t *Tree) elseControl() Node {
   422		t.expect(itemRightDelim, "else")
   423		return newElse(t.lex.lineNumber())
   424	}
   425	
   426	// Template:
   427	//	{{template stringValue pipeline}}
   428	// Template keyword is past.  The name must be something that can evaluate
   429	// to a string.
   430	func (t *Tree) templateControl() Node {
   431		var name string
   432		switch token := t.next(); token.typ {
   433		case itemString, itemRawString:
   434			s, err := strconv.Unquote(token.val)
   435			if err != nil {
   436				t.error(err)
   437			}
   438			name = s
   439		default:
   440			t.unexpected(token, "template invocation")
   441		}
   442		var pipe *PipeNode
   443		if t.next().typ != itemRightDelim {
   444			t.backup()
   445			// Do not pop variables; they persist until "end".
   446			pipe = t.pipeline("template")
   447		}
   448		return newTemplate(t.lex.lineNumber(), name, pipe)
   449	}
   450	
   451	// command:
   452	// space-separated arguments up to a pipeline character or right delimiter.
   453	// we consume the pipe character but leave the right delim to terminate the action.
   454	func (t *Tree) command() *CommandNode {
   455		cmd := newCommand()
   456	Loop:
   457		for {
   458			switch token := t.next(); token.typ {
   459			case itemRightDelim:
   460				t.backup()
   461				break Loop
   462			case itemPipe:
   463				break Loop
   464			case itemError:
   465				t.errorf("%s", token.val)
   466			case itemIdentifier:
   467				if !t.hasFunction(token.val) {
   468					t.errorf("function %q not defined", token.val)
   469				}
   470				cmd.append(NewIdentifier(token.val))
   471			case itemDot:
   472				cmd.append(newDot())
   473			case itemVariable:
   474				cmd.append(t.useVar(token.val))
   475			case itemField:
   476				cmd.append(newField(token.val))
   477			case itemBool:
   478				cmd.append(newBool(token.val == "true"))
   479			case itemCharConstant, itemComplex, itemNumber:
   480				number, err := newNumber(token.val, token.typ)
   481				if err != nil {
   482					t.error(err)
   483				}
   484				cmd.append(number)
   485			case itemString, itemRawString:
   486				s, err := strconv.Unquote(token.val)
   487				if err != nil {
   488					t.error(err)
   489				}
   490				cmd.append(newString(token.val, s))
   491			default:
   492				t.unexpected(token, "command")
   493			}
   494		}
   495		if len(cmd.Args) == 0 {
   496			t.errorf("empty command")
   497		}
   498		return cmd
   499	}
   500	
   501	// hasFunction reports if a function name exists in the Tree's maps.
   502	func (t *Tree) hasFunction(name string) bool {
   503		for _, funcMap := range t.funcs {
   504			if funcMap == nil {
   505				continue
   506			}
   507			if funcMap[name] != nil {
   508				return true
   509			}
   510		}
   511		return false
   512	}
   513	
   514	// popVars trims the variable list to the specified length
   515	func (t *Tree) popVars(n int) {
   516		t.vars = t.vars[:n]
   517	}
   518	
   519	// useVar returns a node for a variable reference. It errors if the
   520	// variable is not defined.
   521	func (t *Tree) useVar(name string) Node {
   522		v := newVariable(name)
   523		for _, varName := range t.vars {
   524			if varName == v.Ident[0] {
   525				return v
   526			}
   527		}
   528		t.errorf("undefined variable %q", v.Ident[0])
   529		return nil
   530	}