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