github.com/panjjo/go@v0.0.0-20161104043856-d62b31386338/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 } 33 34 // Copy returns a copy of the Tree. Any parsing state is discarded. 35 func (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. 51 func 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. 60 func (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. 70 func (t *Tree) backup() { 71 t.peekCount++ 72 } 73 74 // backup2 backs the input stream up two tokens. 75 // The zeroth token is already there. 76 func (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. 83 func (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. 90 func (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. 100 func (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. 111 func (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. 125 func 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. 135 func (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. 158 func (t *Tree) errorf(format string, args ...interface{}) { 159 t.Root = nil 160 format = fmt.Sprintf("template: %s:%d: %s", t.ParseName, t.lex.lineNumber(), format) 161 panic(fmt.Errorf(format, args...)) 162 } 163 164 // error terminates processing. 165 func (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. 170 func (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. 179 func (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. 188 func (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. 193 func (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 return 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 } 224 225 // Parse parses the template definition string to construct a representation of 226 // the template for execution. If either action delimiter string is empty, the 227 // default ("{{" or "}}") is used. Embedded template definitions are added to 228 // the treeSet map. 229 func (t *Tree) Parse(text, leftDelim, rightDelim string, treeSet map[string]*Tree, funcs ...map[string]interface{}) (tree *Tree, err error) { 230 defer t.recover(&err) 231 t.ParseName = t.Name 232 t.startParse(funcs, lex(t.Name, text, leftDelim, rightDelim), treeSet) 233 t.text = text 234 t.parse() 235 t.add() 236 t.stopParse() 237 return t, nil 238 } 239 240 // add adds tree to t.treeSet. 241 func (t *Tree) add() { 242 tree := t.treeSet[t.Name] 243 if tree == nil || IsEmptyTree(tree.Root) { 244 t.treeSet[t.Name] = t 245 return 246 } 247 if !IsEmptyTree(t.Root) { 248 t.errorf("template: multiple definition of template %q", t.Name) 249 } 250 } 251 252 // IsEmptyTree reports whether this tree (node) is empty of everything but space. 253 func IsEmptyTree(n Node) bool { 254 switch n := n.(type) { 255 case nil: 256 return true 257 case *ActionNode: 258 case *IfNode: 259 case *ListNode: 260 for _, node := range n.Nodes { 261 if !IsEmptyTree(node) { 262 return false 263 } 264 } 265 return true 266 case *RangeNode: 267 case *TemplateNode: 268 case *TextNode: 269 return len(bytes.TrimSpace(n.Text)) == 0 270 case *WithNode: 271 default: 272 panic("unknown node: " + n.String()) 273 } 274 return false 275 } 276 277 // parse is the top-level parser for a template, essentially the same 278 // as itemList except it also parses {{define}} actions. 279 // It runs to EOF. 280 func (t *Tree) parse() { 281 t.Root = t.newList(t.peek().pos) 282 for t.peek().typ != itemEOF { 283 if t.peek().typ == itemLeftDelim { 284 delim := t.next() 285 if t.nextNonSpace().typ == itemDefine { 286 newT := New("definition") // name will be updated once we know it. 287 newT.text = t.text 288 newT.ParseName = t.ParseName 289 newT.startParse(t.funcs, t.lex, t.treeSet) 290 newT.parseDefinition() 291 continue 292 } 293 t.backup2(delim) 294 } 295 switch n := t.textOrAction(); n.Type() { 296 case nodeEnd, nodeElse: 297 t.errorf("unexpected %s", n) 298 default: 299 t.Root.append(n) 300 } 301 } 302 } 303 304 // parseDefinition parses a {{define}} ... {{end}} template definition and 305 // installs the definition in t.treeSet. The "define" keyword has already 306 // been scanned. 307 func (t *Tree) parseDefinition() { 308 const context = "define clause" 309 name := t.expectOneOf(itemString, itemRawString, context) 310 var err error 311 t.Name, err = strconv.Unquote(name.val) 312 if err != nil { 313 t.error(err) 314 } 315 t.expect(itemRightDelim, context) 316 var end Node 317 t.Root, end = t.itemList() 318 if end.Type() != nodeEnd { 319 t.errorf("unexpected %s in %s", end, context) 320 } 321 t.add() 322 t.stopParse() 323 } 324 325 // itemList: 326 // textOrAction* 327 // Terminates at {{end}} or {{else}}, returned separately. 328 func (t *Tree) itemList() (list *ListNode, next Node) { 329 list = t.newList(t.peekNonSpace().pos) 330 for t.peekNonSpace().typ != itemEOF { 331 n := t.textOrAction() 332 switch n.Type() { 333 case nodeEnd, nodeElse: 334 return list, n 335 } 336 list.append(n) 337 } 338 t.errorf("unexpected EOF") 339 return 340 } 341 342 // textOrAction: 343 // text | action 344 func (t *Tree) textOrAction() Node { 345 switch token := t.nextNonSpace(); token.typ { 346 case itemText: 347 return t.newText(token.pos, token.val) 348 case itemLeftDelim: 349 return t.action() 350 default: 351 t.unexpected(token, "input") 352 } 353 return nil 354 } 355 356 // Action: 357 // control 358 // command ("|" command)* 359 // Left delim is past. Now get actions. 360 // First word could be a keyword such as range. 361 func (t *Tree) action() (n Node) { 362 switch token := t.nextNonSpace(); token.typ { 363 case itemBlock: 364 return t.blockControl() 365 case itemElse: 366 return t.elseControl() 367 case itemEnd: 368 return t.endControl() 369 case itemIf: 370 return t.ifControl() 371 case itemRange: 372 return t.rangeControl() 373 case itemTemplate: 374 return t.templateControl() 375 case itemWith: 376 return t.withControl() 377 } 378 t.backup() 379 // Do not pop variables; they persist until "end". 380 return t.newAction(t.peek().pos, t.lex.lineNumber(), t.pipeline("command")) 381 } 382 383 // Pipeline: 384 // declarations? command ('|' command)* 385 func (t *Tree) pipeline(context string) (pipe *PipeNode) { 386 var decl []*VariableNode 387 pos := t.peekNonSpace().pos 388 // Are there declarations? 389 for { 390 if v := t.peekNonSpace(); v.typ == itemVariable { 391 t.next() 392 // Since space is a token, we need 3-token look-ahead here in the worst case: 393 // in "$x foo" we need to read "foo" (as opposed to ":=") to know that $x is an 394 // argument variable rather than a declaration. So remember the token 395 // adjacent to the variable so we can push it back if necessary. 396 tokenAfterVariable := t.peek() 397 if next := t.peekNonSpace(); next.typ == itemColonEquals || (next.typ == itemChar && next.val == ",") { 398 t.nextNonSpace() 399 variable := t.newVariable(v.pos, v.val) 400 decl = append(decl, variable) 401 t.vars = append(t.vars, v.val) 402 if next.typ == itemChar && next.val == "," { 403 if context == "range" && len(decl) < 2 { 404 continue 405 } 406 t.errorf("too many declarations in %s", context) 407 } 408 } else if tokenAfterVariable.typ == itemSpace { 409 t.backup3(v, tokenAfterVariable) 410 } else { 411 t.backup2(v) 412 } 413 } 414 break 415 } 416 pipe = t.newPipeline(pos, t.lex.lineNumber(), decl) 417 for { 418 switch token := t.nextNonSpace(); token.typ { 419 case itemRightDelim, itemRightParen: 420 // At this point, the pipeline is complete 421 t.checkPipeline(pipe, context) 422 if token.typ == itemRightParen { 423 t.backup() 424 } 425 return 426 case itemBool, itemCharConstant, itemComplex, itemDot, itemField, itemIdentifier, 427 itemNumber, itemNil, itemRawString, itemString, itemVariable, itemLeftParen: 428 t.backup() 429 pipe.append(t.command()) 430 default: 431 t.unexpected(token, context) 432 } 433 } 434 } 435 436 func (t *Tree) checkPipeline(pipe *PipeNode, context string) { 437 // Reject empty pipelines 438 if len(pipe.Cmds) == 0 { 439 t.errorf("missing value for %s", context) 440 } 441 // Only the first command of a pipeline can start with a non executable operand 442 for i, c := range pipe.Cmds[1:] { 443 switch c.Args[0].Type() { 444 case NodeBool, NodeDot, NodeNil, NodeNumber, NodeString: 445 // With A|B|C, pipeline stage 2 is B 446 t.errorf("non executable command in pipeline stage %d", i+2) 447 } 448 } 449 } 450 451 func (t *Tree) parseControl(allowElseIf bool, context string) (pos Pos, line int, pipe *PipeNode, list, elseList *ListNode) { 452 defer t.popVars(len(t.vars)) 453 line = t.lex.lineNumber() 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(), 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. 489 func (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. 497 func (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. 505 func (t *Tree) withControl() Node { 506 return t.newWith(t.parseControl(false, "with")) 507 } 508 509 // End: 510 // {{end}} 511 // End keyword is past. 512 func (t *Tree) endControl() Node { 513 return t.newEnd(t.expect(itemRightDelim, "end").pos) 514 } 515 516 // Else: 517 // {{else}} 518 // Else keyword is past. 519 func (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, t.lex.lineNumber()) 525 } 526 return t.newElse(t.expect(itemRightDelim, "else").pos, t.lex.lineNumber()) 527 } 528 529 // Block: 530 // {{block stringValue pipeline}} 531 // Block keyword is past. 532 // The name must be something that can evaluate to a string. 533 // The pipeline is mandatory. 534 func (t *Tree) blockControl() Node { 535 const context = "block clause" 536 537 token := t.nextNonSpace() 538 name := t.parseTemplateName(token, context) 539 pipe := t.pipeline(context) 540 541 block := New(name) // name will be updated once we know it. 542 block.text = t.text 543 block.ParseName = t.ParseName 544 block.startParse(t.funcs, t.lex, t.treeSet) 545 var end Node 546 block.Root, end = block.itemList() 547 if end.Type() != nodeEnd { 548 t.errorf("unexpected %s in %s", end, context) 549 } 550 block.add() 551 block.stopParse() 552 553 return t.newTemplate(token.pos, t.lex.lineNumber(), name, pipe) 554 } 555 556 // Template: 557 // {{template stringValue pipeline}} 558 // Template keyword is past. The name must be something that can evaluate 559 // to a string. 560 func (t *Tree) templateControl() Node { 561 const context = "template clause" 562 token := t.nextNonSpace() 563 name := t.parseTemplateName(token, context) 564 var pipe *PipeNode 565 if t.nextNonSpace().typ != itemRightDelim { 566 t.backup() 567 // Do not pop variables; they persist until "end". 568 pipe = t.pipeline(context) 569 } 570 return t.newTemplate(token.pos, t.lex.lineNumber(), name, pipe) 571 } 572 573 func (t *Tree) parseTemplateName(token item, context string) (name string) { 574 switch token.typ { 575 case itemString, itemRawString: 576 s, err := strconv.Unquote(token.val) 577 if err != nil { 578 t.error(err) 579 } 580 name = s 581 default: 582 t.unexpected(token, context) 583 } 584 return 585 } 586 587 // command: 588 // operand (space operand)* 589 // space-separated arguments up to a pipeline character or right delimiter. 590 // we consume the pipe character but leave the right delim to terminate the action. 591 func (t *Tree) command() *CommandNode { 592 cmd := t.newCommand(t.peekNonSpace().pos) 593 for { 594 t.peekNonSpace() // skip leading spaces. 595 operand := t.operand() 596 if operand != nil { 597 cmd.append(operand) 598 } 599 switch token := t.next(); token.typ { 600 case itemSpace: 601 continue 602 case itemError: 603 t.errorf("%s", token.val) 604 case itemRightDelim, itemRightParen: 605 t.backup() 606 case itemPipe: 607 default: 608 t.errorf("unexpected %s in operand", token) 609 } 610 break 611 } 612 if len(cmd.Args) == 0 { 613 t.errorf("empty command") 614 } 615 return cmd 616 } 617 618 // operand: 619 // term .Field* 620 // An operand is a space-separated component of a command, 621 // a term possibly followed by field accesses. 622 // A nil return means the next item is not an operand. 623 func (t *Tree) operand() Node { 624 node := t.term() 625 if node == nil { 626 return nil 627 } 628 if t.peek().typ == itemField { 629 chain := t.newChain(t.peek().pos, node) 630 for t.peek().typ == itemField { 631 chain.Add(t.next().val) 632 } 633 // Compatibility with original API: If the term is of type NodeField 634 // or NodeVariable, just put more fields on the original. 635 // Otherwise, keep the Chain node. 636 // Obvious parsing errors involving literal values are detected here. 637 // More complex error cases will have to be handled at execution time. 638 switch node.Type() { 639 case NodeField: 640 node = t.newField(chain.Position(), chain.String()) 641 case NodeVariable: 642 node = t.newVariable(chain.Position(), chain.String()) 643 case NodeBool, NodeString, NodeNumber, NodeNil, NodeDot: 644 t.errorf("unexpected . after term %q", node.String()) 645 default: 646 node = chain 647 } 648 } 649 return node 650 } 651 652 // term: 653 // literal (number, string, nil, boolean) 654 // function (identifier) 655 // . 656 // .Field 657 // $ 658 // '(' pipeline ')' 659 // A term is a simple "expression". 660 // A nil return means the next item is not a term. 661 func (t *Tree) term() Node { 662 switch token := t.nextNonSpace(); token.typ { 663 case itemError: 664 t.errorf("%s", token.val) 665 case itemIdentifier: 666 if !t.hasFunction(token.val) { 667 t.errorf("function %q not defined", token.val) 668 } 669 return NewIdentifier(token.val).SetTree(t).SetPos(token.pos) 670 case itemDot: 671 return t.newDot(token.pos) 672 case itemNil: 673 return t.newNil(token.pos) 674 case itemVariable: 675 return t.useVar(token.pos, token.val) 676 case itemField: 677 return t.newField(token.pos, token.val) 678 case itemBool: 679 return t.newBool(token.pos, token.val == "true") 680 case itemCharConstant, itemComplex, itemNumber: 681 number, err := t.newNumber(token.pos, token.val, token.typ) 682 if err != nil { 683 t.error(err) 684 } 685 return number 686 case itemLeftParen: 687 pipe := t.pipeline("parenthesized pipeline") 688 if token := t.next(); token.typ != itemRightParen { 689 t.errorf("unclosed right paren: unexpected %s", token) 690 } 691 return pipe 692 case itemString, itemRawString: 693 s, err := strconv.Unquote(token.val) 694 if err != nil { 695 t.error(err) 696 } 697 return t.newString(token.pos, token.val, s) 698 } 699 t.backup() 700 return nil 701 } 702 703 // hasFunction reports if a function name exists in the Tree's maps. 704 func (t *Tree) hasFunction(name string) bool { 705 for _, funcMap := range t.funcs { 706 if funcMap == nil { 707 continue 708 } 709 if funcMap[name] != nil { 710 return true 711 } 712 } 713 return false 714 } 715 716 // popVars trims the variable list to the specified length 717 func (t *Tree) popVars(n int) { 718 t.vars = t.vars[:n] 719 } 720 721 // useVar returns a node for a variable reference. It errors if the 722 // variable is not defined. 723 func (t *Tree) useVar(pos Pos, name string) Node { 724 v := t.newVariable(pos, name) 725 for _, varName := range t.vars { 726 if varName == v.Ident[0] { 727 return v 728 } 729 } 730 t.errorf("undefined variable %q", v.Ident[0]) 731 return nil 732 }