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 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. 38type Mode uint 39 40const ( 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. 46func (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. 62func 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. 71func (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. 81func (t *Tree) backup() { 82 t.peekCount++ 83} 84 85// backup2 backs the input stream up two tokens. 86// The zeroth token is already there. 87func (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. 94func (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. 101func (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. 111func (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. 122func (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. 131func 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. 141func (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. 161func (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. 168func (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. 173func (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. 182func (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. 191func (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. 206func (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. 221func (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. 230func (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. 241func (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. 254func (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. 266func 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. 295func (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. 323func (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. 344func (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 360func (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 376func (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. 385func (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)* 410func (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? 414decls: 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 465func (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 480func (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. 517func (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. 525func (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. 533func (t *Tree) withControl() Node { 534 return t.newWith(t.parseControl(false, "with")) 535} 536 537// End: 538// {{end}} 539// End keyword is past. 540func (t *Tree) endControl() Node { 541 return t.newEnd(t.expect(itemRightDelim, "end").pos) 542} 543 544// Else: 545// {{else}} 546// Else keyword is past. 547func (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. 563func (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. 590func (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 603func (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. 621func (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. 652func (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. 690func (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. 728func (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 741func (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. 747func (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