libgo: update to go1.9
[official-gcc.git] / libgo / go / text / template / parse / parse.go
bloba91a544ce016f2c5446c441dcc30a3abf5d39966
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.
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
11 import (
12 "bytes"
13 "fmt"
14 "runtime"
15 "strconv"
16 "strings"
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
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
39 return &Tree{
40 Name: t.Name,
41 ParseName: t.ParseName,
42 Root: t.Root.CopyList(),
43 text: t.text,
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
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()
66 return t.token[t.peekCount]
69 // backup backs the input stream up one token.
70 func (t *Tree) backup() {
71 t.peekCount++
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
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
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]
94 t.peekCount = 1
95 t.token[0] = t.lex.nextItem()
96 return t.token[0]
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
107 return token
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
118 t.backup()
119 return token
122 // Parsing.
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,
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
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
149 lineNum := 1 + strings.Count(text, "\n")
150 context = n.String()
151 if len(context) > 20 {
152 context = fmt.Sprintf("%.20s...", context)
154 return fmt.Sprintf("%s:%d:%d", tree.ParseName, lineNum, byteNum), context
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.token[0].line, format)
161 panic(fmt.Errorf(format, args...))
164 // error terminates processing.
165 func (t *Tree) error(err error) {
166 t.errorf("%s", err)
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)
175 return token
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)
184 return token
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)
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)
199 if t != nil {
200 t.lex.drain()
201 t.stopParse()
203 *errp = e.(error)
207 // startParse initializes the parser, using the lexer.
208 func (t *Tree) startParse(funcs []map[string]interface{}, lex *lexer, treeSet map[string]*Tree) {
209 t.Root = nil
210 t.lex = lex
211 t.vars = []string{"$"}
212 t.funcs = funcs
213 t.treeSet = treeSet
216 // stopParse terminates parsing.
217 func (t *Tree) stopParse() {
218 t.lex = nil
219 t.vars = nil
220 t.funcs = nil
221 t.treeSet = nil
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), treeSet)
232 t.text = text
233 t.parse()
234 t.add()
235 t.stopParse()
236 return t, nil
239 // add adds tree to t.treeSet.
240 func (t *Tree) add() {
241 tree := t.treeSet[t.Name]
242 if tree == nil || IsEmptyTree(tree.Root) {
243 t.treeSet[t.Name] = t
244 return
246 if !IsEmptyTree(t.Root) {
247 t.errorf("template: multiple definition of template %q", t.Name)
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
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())
273 return false
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() {
280 t.Root = t.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, t.treeSet)
289 newT.parseDefinition()
290 continue
292 t.backup2(delim)
294 switch n := t.textOrAction(); n.Type() {
295 case nodeEnd, nodeElse:
296 t.errorf("unexpected %s", n)
297 default:
298 t.Root.append(n)
303 // parseDefinition parses a {{define}} ... {{end}} template definition and
304 // installs the definition in t.treeSet. The "define" keyword has already
305 // been scanned.
306 func (t *Tree) parseDefinition() {
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)
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)
320 t.add()
321 t.stopParse()
324 // itemList:
325 // textOrAction*
326 // Terminates at {{end}} or {{else}}, returned separately.
327 func (t *Tree) itemList() (list *ListNode, next Node) {
328 list = t.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
335 list.append(n)
337 t.errorf("unexpected EOF")
338 return
341 // textOrAction:
342 // text | action
343 func (t *Tree) textOrAction() Node {
344 switch token := t.nextNonSpace(); token.typ {
345 case itemText:
346 return t.newText(token.pos, token.val)
347 case itemLeftDelim:
348 return t.action()
349 default:
350 t.unexpected(token, "input")
352 return nil
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 itemBlock:
363 return t.blockControl()
364 case itemElse:
365 return t.elseControl()
366 case itemEnd:
367 return t.endControl()
368 case itemIf:
369 return t.ifControl()
370 case itemRange:
371 return t.rangeControl()
372 case itemTemplate:
373 return t.templateControl()
374 case itemWith:
375 return t.withControl()
377 t.backup()
378 token := t.peek()
379 // Do not pop variables; they persist until "end".
380 return t.newAction(token.pos, token.line, t.pipeline("command"))
383 // Pipeline:
384 // declarations? command ('|' command)*
385 func (t *Tree) pipeline(context string) (pipe *PipeNode) {
386 var decl []*VariableNode
387 token := t.peekNonSpace()
388 pos := token.pos
389 // Are there declarations?
390 for {
391 if v := t.peekNonSpace(); v.typ == itemVariable {
392 t.next()
393 // Since space is a token, we need 3-token look-ahead here in the worst case:
394 // in "$x foo" we need to read "foo" (as opposed to ":=") to know that $x is an
395 // argument variable rather than a declaration. So remember the token
396 // adjacent to the variable so we can push it back if necessary.
397 tokenAfterVariable := t.peek()
398 if next := t.peekNonSpace(); next.typ == itemColonEquals || (next.typ == itemChar && next.val == ",") {
399 t.nextNonSpace()
400 variable := t.newVariable(v.pos, v.val)
401 decl = append(decl, variable)
402 t.vars = append(t.vars, v.val)
403 if next.typ == itemChar && next.val == "," {
404 if context == "range" && len(decl) < 2 {
405 continue
407 t.errorf("too many declarations in %s", context)
409 } else if tokenAfterVariable.typ == itemSpace {
410 t.backup3(v, tokenAfterVariable)
411 } else {
412 t.backup2(v)
415 break
417 pipe = t.newPipeline(pos, token.line, decl)
418 for {
419 switch token := t.nextNonSpace(); token.typ {
420 case itemRightDelim, itemRightParen:
421 // At this point, the pipeline is complete
422 t.checkPipeline(pipe, context)
423 if token.typ == itemRightParen {
424 t.backup()
426 return
427 case itemBool, itemCharConstant, itemComplex, itemDot, itemField, itemIdentifier,
428 itemNumber, itemNil, itemRawString, itemString, itemVariable, itemLeftParen:
429 t.backup()
430 pipe.append(t.command())
431 default:
432 t.unexpected(token, context)
437 func (t *Tree) checkPipeline(pipe *PipeNode, context string) {
438 // Reject empty pipelines
439 if len(pipe.Cmds) == 0 {
440 t.errorf("missing value for %s", context)
442 // Only the first command of a pipeline can start with a non executable operand
443 for i, c := range pipe.Cmds[1:] {
444 switch c.Args[0].Type() {
445 case NodeBool, NodeDot, NodeNil, NodeNumber, NodeString:
446 // With A|B|C, pipeline stage 2 is B
447 t.errorf("non executable command in pipeline stage %d", i+2)
452 func (t *Tree) parseControl(allowElseIf bool, context string) (pos Pos, line int, pipe *PipeNode, list, elseList *ListNode) {
453 defer t.popVars(len(t.vars))
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
477 elseList, next = t.itemList()
478 if next.Type() != nodeEnd {
479 t.errorf("expected end; found %s", next)
482 return pipe.Position(), pipe.Line, pipe, list, elseList
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"))
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"))
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"))
509 // End:
510 // {{end}}
511 // End keyword is past.
512 func (t *Tree) endControl() Node {
513 return t.newEnd(t.expect(itemRightDelim, "end").pos)
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, peek.line)
526 token := t.expect(itemRightDelim, "else")
527 return t.newElse(token.pos, token.line)
530 // Block:
531 // {{block stringValue pipeline}}
532 // Block keyword is past.
533 // The name must be something that can evaluate to a string.
534 // The pipeline is mandatory.
535 func (t *Tree) blockControl() Node {
536 const context = "block clause"
538 token := t.nextNonSpace()
539 name := t.parseTemplateName(token, context)
540 pipe := t.pipeline(context)
542 block := New(name) // name will be updated once we know it.
543 block.text = t.text
544 block.ParseName = t.ParseName
545 block.startParse(t.funcs, t.lex, t.treeSet)
546 var end Node
547 block.Root, end = block.itemList()
548 if end.Type() != nodeEnd {
549 t.errorf("unexpected %s in %s", end, context)
551 block.add()
552 block.stopParse()
554 return t.newTemplate(token.pos, token.line, name, pipe)
557 // Template:
558 // {{template stringValue pipeline}}
559 // Template keyword is past. The name must be something that can evaluate
560 // to a string.
561 func (t *Tree) templateControl() Node {
562 const context = "template clause"
563 token := t.nextNonSpace()
564 name := t.parseTemplateName(token, context)
565 var pipe *PipeNode
566 if t.nextNonSpace().typ != itemRightDelim {
567 t.backup()
568 // Do not pop variables; they persist until "end".
569 pipe = t.pipeline(context)
571 return t.newTemplate(token.pos, token.line, name, pipe)
574 func (t *Tree) parseTemplateName(token item, context string) (name string) {
575 switch token.typ {
576 case itemString, itemRawString:
577 s, err := strconv.Unquote(token.val)
578 if err != nil {
579 t.error(err)
581 name = s
582 default:
583 t.unexpected(token, context)
585 return
588 // command:
589 // operand (space operand)*
590 // space-separated arguments up to a pipeline character or right delimiter.
591 // we consume the pipe character but leave the right delim to terminate the action.
592 func (t *Tree) command() *CommandNode {
593 cmd := t.newCommand(t.peekNonSpace().pos)
594 for {
595 t.peekNonSpace() // skip leading spaces.
596 operand := t.operand()
597 if operand != nil {
598 cmd.append(operand)
600 switch token := t.next(); token.typ {
601 case itemSpace:
602 continue
603 case itemError:
604 t.errorf("%s", token.val)
605 case itemRightDelim, itemRightParen:
606 t.backup()
607 case itemPipe:
608 default:
609 t.errorf("unexpected %s in operand", token)
611 break
613 if len(cmd.Args) == 0 {
614 t.errorf("empty command")
616 return cmd
619 // operand:
620 // term .Field*
621 // An operand is a space-separated component of a command,
622 // a term possibly followed by field accesses.
623 // A nil return means the next item is not an operand.
624 func (t *Tree) operand() Node {
625 node := t.term()
626 if node == nil {
627 return nil
629 if t.peek().typ == itemField {
630 chain := t.newChain(t.peek().pos, node)
631 for t.peek().typ == itemField {
632 chain.Add(t.next().val)
634 // Compatibility with original API: If the term is of type NodeField
635 // or NodeVariable, just put more fields on the original.
636 // Otherwise, keep the Chain node.
637 // Obvious parsing errors involving literal values are detected here.
638 // More complex error cases will have to be handled at execution time.
639 switch node.Type() {
640 case NodeField:
641 node = t.newField(chain.Position(), chain.String())
642 case NodeVariable:
643 node = t.newVariable(chain.Position(), chain.String())
644 case NodeBool, NodeString, NodeNumber, NodeNil, NodeDot:
645 t.errorf("unexpected . after term %q", node.String())
646 default:
647 node = chain
650 return node
653 // term:
654 // literal (number, string, nil, boolean)
655 // function (identifier)
656 // .
657 // .Field
658 // $
659 // '(' pipeline ')'
660 // A term is a simple "expression".
661 // A nil return means the next item is not a term.
662 func (t *Tree) term() Node {
663 switch token := t.nextNonSpace(); token.typ {
664 case itemError:
665 t.errorf("%s", token.val)
666 case itemIdentifier:
667 if !t.hasFunction(token.val) {
668 t.errorf("function %q not defined", token.val)
670 return NewIdentifier(token.val).SetTree(t).SetPos(token.pos)
671 case itemDot:
672 return t.newDot(token.pos)
673 case itemNil:
674 return t.newNil(token.pos)
675 case itemVariable:
676 return t.useVar(token.pos, token.val)
677 case itemField:
678 return t.newField(token.pos, token.val)
679 case itemBool:
680 return t.newBool(token.pos, token.val == "true")
681 case itemCharConstant, itemComplex, itemNumber:
682 number, err := t.newNumber(token.pos, token.val, token.typ)
683 if err != nil {
684 t.error(err)
686 return number
687 case itemLeftParen:
688 pipe := t.pipeline("parenthesized pipeline")
689 if token := t.next(); token.typ != itemRightParen {
690 t.errorf("unclosed right paren: unexpected %s", token)
692 return pipe
693 case itemString, itemRawString:
694 s, err := strconv.Unquote(token.val)
695 if err != nil {
696 t.error(err)
698 return t.newString(token.pos, token.val, s)
700 t.backup()
701 return nil
704 // hasFunction reports if a function name exists in the Tree's maps.
705 func (t *Tree) hasFunction(name string) bool {
706 for _, funcMap := range t.funcs {
707 if funcMap == nil {
708 continue
710 if funcMap[name] != nil {
711 return true
714 return false
717 // popVars trims the variable list to the specified length
718 func (t *Tree) popVars(n int) {
719 t.vars = t.vars[:n]
722 // useVar returns a node for a variable reference. It errors if the
723 // variable is not defined.
724 func (t *Tree) useVar(pos Pos, name string) Node {
725 v := t.newVariable(pos, name)
726 for _, varName := range t.vars {
727 if varName == v.Ident[0] {
728 return v
731 t.errorf("undefined variable %q", v.Ident[0])
732 return nil