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