...

Source file src/text/template/parse/parse.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  // 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  )
		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  	ParseName string		// name of the top-level template during parsing, for error messages.
		23  	Root			*ListNode // top-level root of the tree.
		24  	Mode			Mode			// parsing mode.
		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  	treeSet		map[string]*Tree
		33  	actionLine int // line of left delim starting action
		34  	mode			 Mode
		35  }
		36  
		37  // A mode value is a set of flags (or 0). Modes control parser behavior.
		38  type Mode uint
		39  
		40  const (
		41  	ParseComments Mode = 1 << iota // parse comments and add them to AST
		42  	SkipFuncCheck									// do not check that functions are defined
		43  )
		44  
		45  // Copy returns a copy of the Tree. Any parsing state is discarded.
		46  func (t *Tree) Copy() *Tree {
		47  	if t == nil {
		48  		return nil
		49  	}
		50  	return &Tree{
		51  		Name:			t.Name,
		52  		ParseName: t.ParseName,
		53  		Root:			t.Root.CopyList(),
		54  		text:			t.text,
		55  	}
		56  }
		57  
		58  // Parse returns a map from template name to parse.Tree, created by parsing the
		59  // templates described in the argument string. The top-level template will be
		60  // given the specified name. If an error is encountered, parsing stops and an
		61  // empty map is returned with the error.
		62  func Parse(name, text, leftDelim, rightDelim string, funcs ...map[string]interface{}) (map[string]*Tree, error) {
		63  	treeSet := make(map[string]*Tree)
		64  	t := New(name)
		65  	t.text = text
		66  	_, err := t.Parse(text, leftDelim, rightDelim, treeSet, funcs...)
		67  	return treeSet, err
		68  }
		69  
		70  // next returns the next token.
		71  func (t *Tree) next() item {
		72  	if t.peekCount > 0 {
		73  		t.peekCount--
		74  	} else {
		75  		t.token[0] = t.lex.nextItem()
		76  	}
		77  	return t.token[t.peekCount]
		78  }
		79  
		80  // backup backs the input stream up one token.
		81  func (t *Tree) backup() {
		82  	t.peekCount++
		83  }
		84  
		85  // backup2 backs the input stream up two tokens.
		86  // The zeroth token is already there.
		87  func (t *Tree) backup2(t1 item) {
		88  	t.token[1] = t1
		89  	t.peekCount = 2
		90  }
		91  
		92  // backup3 backs the input stream up three tokens
		93  // The zeroth token is already there.
		94  func (t *Tree) backup3(t2, t1 item) { // Reverse order: we're pushing back.
		95  	t.token[1] = t1
		96  	t.token[2] = t2
		97  	t.peekCount = 3
		98  }
		99  
	 100  // peek returns but does not consume the next token.
	 101  func (t *Tree) peek() item {
	 102  	if t.peekCount > 0 {
	 103  		return t.token[t.peekCount-1]
	 104  	}
	 105  	t.peekCount = 1
	 106  	t.token[0] = t.lex.nextItem()
	 107  	return t.token[0]
	 108  }
	 109  
	 110  // nextNonSpace returns the next non-space token.
	 111  func (t *Tree) nextNonSpace() (token item) {
	 112  	for {
	 113  		token = t.next()
	 114  		if token.typ != itemSpace {
	 115  			break
	 116  		}
	 117  	}
	 118  	return token
	 119  }
	 120  
	 121  // peekNonSpace returns but does not consume the next non-space token.
	 122  func (t *Tree) peekNonSpace() item {
	 123  	token := t.nextNonSpace()
	 124  	t.backup()
	 125  	return token
	 126  }
	 127  
	 128  // Parsing.
	 129  
	 130  // New allocates a new parse tree with the given name.
	 131  func New(name string, funcs ...map[string]interface{}) *Tree {
	 132  	return &Tree{
	 133  		Name:	name,
	 134  		funcs: funcs,
	 135  	}
	 136  }
	 137  
	 138  // ErrorContext returns a textual representation of the location of the node in the input text.
	 139  // The receiver is only used when the node does not have a pointer to the tree inside,
	 140  // which can occur in old code.
	 141  func (t *Tree) ErrorContext(n Node) (location, context string) {
	 142  	pos := int(n.Position())
	 143  	tree := n.tree()
	 144  	if tree == nil {
	 145  		tree = t
	 146  	}
	 147  	text := tree.text[:pos]
	 148  	byteNum := strings.LastIndex(text, "\n")
	 149  	if byteNum == -1 {
	 150  		byteNum = pos // On first line.
	 151  	} else {
	 152  		byteNum++ // After the newline.
	 153  		byteNum = pos - byteNum
	 154  	}
	 155  	lineNum := 1 + strings.Count(text, "\n")
	 156  	context = n.String()
	 157  	return fmt.Sprintf("%s:%d:%d", tree.ParseName, lineNum, byteNum), context
	 158  }
	 159  
	 160  // errorf formats the error and terminates processing.
	 161  func (t *Tree) errorf(format string, args ...interface{}) {
	 162  	t.Root = nil
	 163  	format = fmt.Sprintf("template: %s:%d: %s", t.ParseName, t.token[0].line, format)
	 164  	panic(fmt.Errorf(format, args...))
	 165  }
	 166  
	 167  // error terminates processing.
	 168  func (t *Tree) error(err error) {
	 169  	t.errorf("%s", err)
	 170  }
	 171  
	 172  // expect consumes the next token and guarantees it has the required type.
	 173  func (t *Tree) expect(expected itemType, context string) item {
	 174  	token := t.nextNonSpace()
	 175  	if token.typ != expected {
	 176  		t.unexpected(token, context)
	 177  	}
	 178  	return token
	 179  }
	 180  
	 181  // expectOneOf consumes the next token and guarantees it has one of the required types.
	 182  func (t *Tree) expectOneOf(expected1, expected2 itemType, context string) item {
	 183  	token := t.nextNonSpace()
	 184  	if token.typ != expected1 && token.typ != expected2 {
	 185  		t.unexpected(token, context)
	 186  	}
	 187  	return token
	 188  }
	 189  
	 190  // unexpected complains about the token and terminates processing.
	 191  func (t *Tree) unexpected(token item, context string) {
	 192  	if token.typ == itemError {
	 193  		extra := ""
	 194  		if t.actionLine != 0 && t.actionLine != token.line {
	 195  			extra = fmt.Sprintf(" in action started at %s:%d", t.ParseName, t.actionLine)
	 196  			if strings.HasSuffix(token.val, " action") {
	 197  				extra = extra[len(" in action"):] // avoid "action in action"
	 198  			}
	 199  		}
	 200  		t.errorf("%s%s", token, extra)
	 201  	}
	 202  	t.errorf("unexpected %s in %s", token, context)
	 203  }
	 204  
	 205  // recover is the handler that turns panics into returns from the top level of Parse.
	 206  func (t *Tree) recover(errp *error) {
	 207  	e := recover()
	 208  	if e != nil {
	 209  		if _, ok := e.(runtime.Error); ok {
	 210  			panic(e)
	 211  		}
	 212  		if t != nil {
	 213  			t.lex.drain()
	 214  			t.stopParse()
	 215  		}
	 216  		*errp = e.(error)
	 217  	}
	 218  }
	 219  
	 220  // startParse initializes the parser, using the lexer.
	 221  func (t *Tree) startParse(funcs []map[string]interface{}, lex *lexer, treeSet map[string]*Tree) {
	 222  	t.Root = nil
	 223  	t.lex = lex
	 224  	t.vars = []string{"$"}
	 225  	t.funcs = funcs
	 226  	t.treeSet = treeSet
	 227  }
	 228  
	 229  // stopParse terminates parsing.
	 230  func (t *Tree) stopParse() {
	 231  	t.lex = nil
	 232  	t.vars = nil
	 233  	t.funcs = nil
	 234  	t.treeSet = nil
	 235  }
	 236  
	 237  // Parse parses the template definition string to construct a representation of
	 238  // the template for execution. If either action delimiter string is empty, the
	 239  // default ("{{" or "}}") is used. Embedded template definitions are added to
	 240  // the treeSet map.
	 241  func (t *Tree) Parse(text, leftDelim, rightDelim string, treeSet map[string]*Tree, funcs ...map[string]interface{}) (tree *Tree, err error) {
	 242  	defer t.recover(&err)
	 243  	t.ParseName = t.Name
	 244  	emitComment := t.Mode&ParseComments != 0
	 245  	t.startParse(funcs, lex(t.Name, text, leftDelim, rightDelim, emitComment), treeSet)
	 246  	t.text = text
	 247  	t.parse()
	 248  	t.add()
	 249  	t.stopParse()
	 250  	return t, nil
	 251  }
	 252  
	 253  // add adds tree to t.treeSet.
	 254  func (t *Tree) add() {
	 255  	tree := t.treeSet[t.Name]
	 256  	if tree == nil || IsEmptyTree(tree.Root) {
	 257  		t.treeSet[t.Name] = t
	 258  		return
	 259  	}
	 260  	if !IsEmptyTree(t.Root) {
	 261  		t.errorf("template: multiple definition of template %q", t.Name)
	 262  	}
	 263  }
	 264  
	 265  // IsEmptyTree reports whether this tree (node) is empty of everything but space or comments.
	 266  func IsEmptyTree(n Node) bool {
	 267  	switch n := n.(type) {
	 268  	case nil:
	 269  		return true
	 270  	case *ActionNode:
	 271  	case *CommentNode:
	 272  		return true
	 273  	case *IfNode:
	 274  	case *ListNode:
	 275  		for _, node := range n.Nodes {
	 276  			if !IsEmptyTree(node) {
	 277  				return false
	 278  			}
	 279  		}
	 280  		return true
	 281  	case *RangeNode:
	 282  	case *TemplateNode:
	 283  	case *TextNode:
	 284  		return len(bytes.TrimSpace(n.Text)) == 0
	 285  	case *WithNode:
	 286  	default:
	 287  		panic("unknown node: " + n.String())
	 288  	}
	 289  	return false
	 290  }
	 291  
	 292  // parse is the top-level parser for a template, essentially the same
	 293  // as itemList except it also parses {{define}} actions.
	 294  // It runs to EOF.
	 295  func (t *Tree) parse() {
	 296  	t.Root = t.newList(t.peek().pos)
	 297  	for t.peek().typ != itemEOF {
	 298  		if t.peek().typ == itemLeftDelim {
	 299  			delim := t.next()
	 300  			if t.nextNonSpace().typ == itemDefine {
	 301  				newT := New("definition") // name will be updated once we know it.
	 302  				newT.text = t.text
	 303  				newT.Mode = t.Mode
	 304  				newT.ParseName = t.ParseName
	 305  				newT.startParse(t.funcs, t.lex, t.treeSet)
	 306  				newT.parseDefinition()
	 307  				continue
	 308  			}
	 309  			t.backup2(delim)
	 310  		}
	 311  		switch n := t.textOrAction(); n.Type() {
	 312  		case nodeEnd, nodeElse:
	 313  			t.errorf("unexpected %s", n)
	 314  		default:
	 315  			t.Root.append(n)
	 316  		}
	 317  	}
	 318  }
	 319  
	 320  // parseDefinition parses a {{define}} ...	{{end}} template definition and
	 321  // installs the definition in t.treeSet. The "define" keyword has already
	 322  // been scanned.
	 323  func (t *Tree) parseDefinition() {
	 324  	const context = "define clause"
	 325  	name := t.expectOneOf(itemString, itemRawString, context)
	 326  	var err error
	 327  	t.Name, err = strconv.Unquote(name.val)
	 328  	if err != nil {
	 329  		t.error(err)
	 330  	}
	 331  	t.expect(itemRightDelim, context)
	 332  	var end Node
	 333  	t.Root, end = t.itemList()
	 334  	if end.Type() != nodeEnd {
	 335  		t.errorf("unexpected %s in %s", end, context)
	 336  	}
	 337  	t.add()
	 338  	t.stopParse()
	 339  }
	 340  
	 341  // itemList:
	 342  //	textOrAction*
	 343  // Terminates at {{end}} or {{else}}, returned separately.
	 344  func (t *Tree) itemList() (list *ListNode, next Node) {
	 345  	list = t.newList(t.peekNonSpace().pos)
	 346  	for t.peekNonSpace().typ != itemEOF {
	 347  		n := t.textOrAction()
	 348  		switch n.Type() {
	 349  		case nodeEnd, nodeElse:
	 350  			return list, n
	 351  		}
	 352  		list.append(n)
	 353  	}
	 354  	t.errorf("unexpected EOF")
	 355  	return
	 356  }
	 357  
	 358  // textOrAction:
	 359  //	text | comment | action
	 360  func (t *Tree) textOrAction() Node {
	 361  	switch token := t.nextNonSpace(); token.typ {
	 362  	case itemText:
	 363  		return t.newText(token.pos, token.val)
	 364  	case itemLeftDelim:
	 365  		t.actionLine = token.line
	 366  		defer t.clearActionLine()
	 367  		return t.action()
	 368  	case itemComment:
	 369  		return t.newComment(token.pos, token.val)
	 370  	default:
	 371  		t.unexpected(token, "input")
	 372  	}
	 373  	return nil
	 374  }
	 375  
	 376  func (t *Tree) clearActionLine() {
	 377  	t.actionLine = 0
	 378  }
	 379  
	 380  // Action:
	 381  //	control
	 382  //	command ("|" command)*
	 383  // Left delim is past. Now get actions.
	 384  // First word could be a keyword such as range.
	 385  func (t *Tree) action() (n Node) {
	 386  	switch token := t.nextNonSpace(); token.typ {
	 387  	case itemBlock:
	 388  		return t.blockControl()
	 389  	case itemElse:
	 390  		return t.elseControl()
	 391  	case itemEnd:
	 392  		return t.endControl()
	 393  	case itemIf:
	 394  		return t.ifControl()
	 395  	case itemRange:
	 396  		return t.rangeControl()
	 397  	case itemTemplate:
	 398  		return t.templateControl()
	 399  	case itemWith:
	 400  		return t.withControl()
	 401  	}
	 402  	t.backup()
	 403  	token := t.peek()
	 404  	// Do not pop variables; they persist until "end".
	 405  	return t.newAction(token.pos, token.line, t.pipeline("command", itemRightDelim))
	 406  }
	 407  
	 408  // Pipeline:
	 409  //	declarations? command ('|' command)*
	 410  func (t *Tree) pipeline(context string, end itemType) (pipe *PipeNode) {
	 411  	token := t.peekNonSpace()
	 412  	pipe = t.newPipeline(token.pos, token.line, nil)
	 413  	// Are there declarations or assignments?
	 414  decls:
	 415  	if v := t.peekNonSpace(); v.typ == itemVariable {
	 416  		t.next()
	 417  		// Since space is a token, we need 3-token look-ahead here in the worst case:
	 418  		// in "$x foo" we need to read "foo" (as opposed to ":=") to know that $x is an
	 419  		// argument variable rather than a declaration. So remember the token
	 420  		// adjacent to the variable so we can push it back if necessary.
	 421  		tokenAfterVariable := t.peek()
	 422  		next := t.peekNonSpace()
	 423  		switch {
	 424  		case next.typ == itemAssign, next.typ == itemDeclare:
	 425  			pipe.IsAssign = next.typ == itemAssign
	 426  			t.nextNonSpace()
	 427  			pipe.Decl = append(pipe.Decl, t.newVariable(v.pos, v.val))
	 428  			t.vars = append(t.vars, v.val)
	 429  		case next.typ == itemChar && next.val == ",":
	 430  			t.nextNonSpace()
	 431  			pipe.Decl = append(pipe.Decl, t.newVariable(v.pos, v.val))
	 432  			t.vars = append(t.vars, v.val)
	 433  			if context == "range" && len(pipe.Decl) < 2 {
	 434  				switch t.peekNonSpace().typ {
	 435  				case itemVariable, itemRightDelim, itemRightParen:
	 436  					// second initialized variable in a range pipeline
	 437  					goto decls
	 438  				default:
	 439  					t.errorf("range can only initialize variables")
	 440  				}
	 441  			}
	 442  			t.errorf("too many declarations in %s", context)
	 443  		case tokenAfterVariable.typ == itemSpace:
	 444  			t.backup3(v, tokenAfterVariable)
	 445  		default:
	 446  			t.backup2(v)
	 447  		}
	 448  	}
	 449  	for {
	 450  		switch token := t.nextNonSpace(); token.typ {
	 451  		case end:
	 452  			// At this point, the pipeline is complete
	 453  			t.checkPipeline(pipe, context)
	 454  			return
	 455  		case itemBool, itemCharConstant, itemComplex, itemDot, itemField, itemIdentifier,
	 456  			itemNumber, itemNil, itemRawString, itemString, itemVariable, itemLeftParen:
	 457  			t.backup()
	 458  			pipe.append(t.command())
	 459  		default:
	 460  			t.unexpected(token, context)
	 461  		}
	 462  	}
	 463  }
	 464  
	 465  func (t *Tree) checkPipeline(pipe *PipeNode, context string) {
	 466  	// Reject empty pipelines
	 467  	if len(pipe.Cmds) == 0 {
	 468  		t.errorf("missing value for %s", context)
	 469  	}
	 470  	// Only the first command of a pipeline can start with a non executable operand
	 471  	for i, c := range pipe.Cmds[1:] {
	 472  		switch c.Args[0].Type() {
	 473  		case NodeBool, NodeDot, NodeNil, NodeNumber, NodeString:
	 474  			// With A|B|C, pipeline stage 2 is B
	 475  			t.errorf("non executable command in pipeline stage %d", i+2)
	 476  		}
	 477  	}
	 478  }
	 479  
	 480  func (t *Tree) parseControl(allowElseIf bool, context string) (pos Pos, line int, pipe *PipeNode, list, elseList *ListNode) {
	 481  	defer t.popVars(len(t.vars))
	 482  	pipe = t.pipeline(context, itemRightDelim)
	 483  	var next Node
	 484  	list, next = t.itemList()
	 485  	switch next.Type() {
	 486  	case nodeEnd: //done
	 487  	case nodeElse:
	 488  		if allowElseIf {
	 489  			// Special case for "else if". If the "else" is followed immediately by an "if",
	 490  			// the elseControl will have left the "if" token pending. Treat
	 491  			//	{{if a}}_{{else if b}}_{{end}}
	 492  			// as
	 493  			//	{{if a}}_{{else}}{{if b}}_{{end}}{{end}}.
	 494  			// To do this, parse the if as usual and stop at it {{end}}; the subsequent{{end}}
	 495  			// is assumed. This technique works even for long if-else-if chains.
	 496  			// TODO: Should we allow else-if in with and range?
	 497  			if t.peek().typ == itemIf {
	 498  				t.next() // Consume the "if" token.
	 499  				elseList = t.newList(next.Position())
	 500  				elseList.append(t.ifControl())
	 501  				// Do not consume the next item - only one {{end}} required.
	 502  				break
	 503  			}
	 504  		}
	 505  		elseList, next = t.itemList()
	 506  		if next.Type() != nodeEnd {
	 507  			t.errorf("expected end; found %s", next)
	 508  		}
	 509  	}
	 510  	return pipe.Position(), pipe.Line, pipe, list, elseList
	 511  }
	 512  
	 513  // If:
	 514  //	{{if pipeline}} itemList {{end}}
	 515  //	{{if pipeline}} itemList {{else}} itemList {{end}}
	 516  // If keyword is past.
	 517  func (t *Tree) ifControl() Node {
	 518  	return t.newIf(t.parseControl(true, "if"))
	 519  }
	 520  
	 521  // Range:
	 522  //	{{range pipeline}} itemList {{end}}
	 523  //	{{range pipeline}} itemList {{else}} itemList {{end}}
	 524  // Range keyword is past.
	 525  func (t *Tree) rangeControl() Node {
	 526  	return t.newRange(t.parseControl(false, "range"))
	 527  }
	 528  
	 529  // With:
	 530  //	{{with pipeline}} itemList {{end}}
	 531  //	{{with pipeline}} itemList {{else}} itemList {{end}}
	 532  // If keyword is past.
	 533  func (t *Tree) withControl() Node {
	 534  	return t.newWith(t.parseControl(false, "with"))
	 535  }
	 536  
	 537  // End:
	 538  //	{{end}}
	 539  // End keyword is past.
	 540  func (t *Tree) endControl() Node {
	 541  	return t.newEnd(t.expect(itemRightDelim, "end").pos)
	 542  }
	 543  
	 544  // Else:
	 545  //	{{else}}
	 546  // Else keyword is past.
	 547  func (t *Tree) elseControl() Node {
	 548  	// Special case for "else if".
	 549  	peek := t.peekNonSpace()
	 550  	if peek.typ == itemIf {
	 551  		// We see "{{else if ... " but in effect rewrite it to {{else}}{{if ... ".
	 552  		return t.newElse(peek.pos, peek.line)
	 553  	}
	 554  	token := t.expect(itemRightDelim, "else")
	 555  	return t.newElse(token.pos, token.line)
	 556  }
	 557  
	 558  // Block:
	 559  //	{{block stringValue pipeline}}
	 560  // Block keyword is past.
	 561  // The name must be something that can evaluate to a string.
	 562  // The pipeline is mandatory.
	 563  func (t *Tree) blockControl() Node {
	 564  	const context = "block clause"
	 565  
	 566  	token := t.nextNonSpace()
	 567  	name := t.parseTemplateName(token, context)
	 568  	pipe := t.pipeline(context, itemRightDelim)
	 569  
	 570  	block := New(name) // name will be updated once we know it.
	 571  	block.text = t.text
	 572  	block.Mode = t.Mode
	 573  	block.ParseName = t.ParseName
	 574  	block.startParse(t.funcs, t.lex, t.treeSet)
	 575  	var end Node
	 576  	block.Root, end = block.itemList()
	 577  	if end.Type() != nodeEnd {
	 578  		t.errorf("unexpected %s in %s", end, context)
	 579  	}
	 580  	block.add()
	 581  	block.stopParse()
	 582  
	 583  	return t.newTemplate(token.pos, token.line, name, pipe)
	 584  }
	 585  
	 586  // Template:
	 587  //	{{template stringValue pipeline}}
	 588  // Template keyword is past. The name must be something that can evaluate
	 589  // to a string.
	 590  func (t *Tree) templateControl() Node {
	 591  	const context = "template clause"
	 592  	token := t.nextNonSpace()
	 593  	name := t.parseTemplateName(token, context)
	 594  	var pipe *PipeNode
	 595  	if t.nextNonSpace().typ != itemRightDelim {
	 596  		t.backup()
	 597  		// Do not pop variables; they persist until "end".
	 598  		pipe = t.pipeline(context, itemRightDelim)
	 599  	}
	 600  	return t.newTemplate(token.pos, token.line, name, pipe)
	 601  }
	 602  
	 603  func (t *Tree) parseTemplateName(token item, context string) (name string) {
	 604  	switch token.typ {
	 605  	case itemString, itemRawString:
	 606  		s, err := strconv.Unquote(token.val)
	 607  		if err != nil {
	 608  			t.error(err)
	 609  		}
	 610  		name = s
	 611  	default:
	 612  		t.unexpected(token, context)
	 613  	}
	 614  	return
	 615  }
	 616  
	 617  // command:
	 618  //	operand (space operand)*
	 619  // space-separated arguments up to a pipeline character or right delimiter.
	 620  // we consume the pipe character but leave the right delim to terminate the action.
	 621  func (t *Tree) command() *CommandNode {
	 622  	cmd := t.newCommand(t.peekNonSpace().pos)
	 623  	for {
	 624  		t.peekNonSpace() // skip leading spaces.
	 625  		operand := t.operand()
	 626  		if operand != nil {
	 627  			cmd.append(operand)
	 628  		}
	 629  		switch token := t.next(); token.typ {
	 630  		case itemSpace:
	 631  			continue
	 632  		case itemRightDelim, itemRightParen:
	 633  			t.backup()
	 634  		case itemPipe:
	 635  			// nothing here; break loop below
	 636  		default:
	 637  			t.unexpected(token, "operand")
	 638  		}
	 639  		break
	 640  	}
	 641  	if len(cmd.Args) == 0 {
	 642  		t.errorf("empty command")
	 643  	}
	 644  	return cmd
	 645  }
	 646  
	 647  // operand:
	 648  //	term .Field*
	 649  // An operand is a space-separated component of a command,
	 650  // a term possibly followed by field accesses.
	 651  // A nil return means the next item is not an operand.
	 652  func (t *Tree) operand() Node {
	 653  	node := t.term()
	 654  	if node == nil {
	 655  		return nil
	 656  	}
	 657  	if t.peek().typ == itemField {
	 658  		chain := t.newChain(t.peek().pos, node)
	 659  		for t.peek().typ == itemField {
	 660  			chain.Add(t.next().val)
	 661  		}
	 662  		// Compatibility with original API: If the term is of type NodeField
	 663  		// or NodeVariable, just put more fields on the original.
	 664  		// Otherwise, keep the Chain node.
	 665  		// Obvious parsing errors involving literal values are detected here.
	 666  		// More complex error cases will have to be handled at execution time.
	 667  		switch node.Type() {
	 668  		case NodeField:
	 669  			node = t.newField(chain.Position(), chain.String())
	 670  		case NodeVariable:
	 671  			node = t.newVariable(chain.Position(), chain.String())
	 672  		case NodeBool, NodeString, NodeNumber, NodeNil, NodeDot:
	 673  			t.errorf("unexpected . after term %q", node.String())
	 674  		default:
	 675  			node = chain
	 676  		}
	 677  	}
	 678  	return node
	 679  }
	 680  
	 681  // term:
	 682  //	literal (number, string, nil, boolean)
	 683  //	function (identifier)
	 684  //	.
	 685  //	.Field
	 686  //	$
	 687  //	'(' pipeline ')'
	 688  // A term is a simple "expression".
	 689  // A nil return means the next item is not a term.
	 690  func (t *Tree) term() Node {
	 691  	switch token := t.nextNonSpace(); token.typ {
	 692  	case itemIdentifier:
	 693  		checkFunc := t.Mode&SkipFuncCheck == 0
	 694  		if checkFunc && !t.hasFunction(token.val) {
	 695  			t.errorf("function %q not defined", token.val)
	 696  		}
	 697  		return NewIdentifier(token.val).SetTree(t).SetPos(token.pos)
	 698  	case itemDot:
	 699  		return t.newDot(token.pos)
	 700  	case itemNil:
	 701  		return t.newNil(token.pos)
	 702  	case itemVariable:
	 703  		return t.useVar(token.pos, token.val)
	 704  	case itemField:
	 705  		return t.newField(token.pos, token.val)
	 706  	case itemBool:
	 707  		return t.newBool(token.pos, token.val == "true")
	 708  	case itemCharConstant, itemComplex, itemNumber:
	 709  		number, err := t.newNumber(token.pos, token.val, token.typ)
	 710  		if err != nil {
	 711  			t.error(err)
	 712  		}
	 713  		return number
	 714  	case itemLeftParen:
	 715  		return t.pipeline("parenthesized pipeline", itemRightParen)
	 716  	case itemString, itemRawString:
	 717  		s, err := strconv.Unquote(token.val)
	 718  		if err != nil {
	 719  			t.error(err)
	 720  		}
	 721  		return t.newString(token.pos, token.val, s)
	 722  	}
	 723  	t.backup()
	 724  	return nil
	 725  }
	 726  
	 727  // hasFunction reports if a function name exists in the Tree's maps.
	 728  func (t *Tree) hasFunction(name string) bool {
	 729  	for _, funcMap := range t.funcs {
	 730  		if funcMap == nil {
	 731  			continue
	 732  		}
	 733  		if funcMap[name] != nil {
	 734  			return true
	 735  		}
	 736  	}
	 737  	return false
	 738  }
	 739  
	 740  // popVars trims the variable list to the specified length
	 741  func (t *Tree) popVars(n int) {
	 742  	t.vars = t.vars[:n]
	 743  }
	 744  
	 745  // useVar returns a node for a variable reference. It errors if the
	 746  // variable is not defined.
	 747  func (t *Tree) useVar(pos Pos, name string) Node {
	 748  	v := t.newVariable(pos, name)
	 749  	for _, varName := range t.vars {
	 750  		if varName == v.Ident[0] {
	 751  			return v
	 752  		}
	 753  	}
	 754  	t.errorf("undefined variable %q", v.Ident[0])
	 755  	return nil
	 756  }
	 757  

View as plain text