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