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