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