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