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