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.
19 // Tree is the representation of a single parsed template.
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{}
28 token
[3]item
// three-token lookahead for parser.
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
{
41 ParseName
: t
.ParseName
,
42 Root
: t
.Root
.CopyList(),
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
)
55 _
, err
:= t
.Parse(text
, leftDelim
, rightDelim
, treeSet
, funcs
...)
59 // next returns the next token.
60 func (t
*Tree
) next() item
{
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() {
74 // backup2 backs the input stream up two tokens.
75 // The zeroth token is already there.
76 func (t
*Tree
) backup2(t1 item
) {
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.
89 // peek returns but does not consume the next token.
90 func (t
*Tree
) peek() item
{
92 return t
.token
[t
.peekCount
-1]
95 t
.token
[0] = t
.lex
.nextItem()
99 // nextNonSpace returns the next non-space token.
100 func (t
*Tree
) nextNonSpace() (token item
) {
103 if token
.typ
!= itemSpace
{
110 // peekNonSpace returns but does not consume the next non-space token.
111 func (t
*Tree
) peekNonSpace() (token item
) {
114 if token
.typ
!= itemSpace
{
124 // New allocates a new parse tree with the given name.
125 func New(name
string, funcs
...map[string]interface{}) *Tree
{
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())
141 text
:= tree
.text
[:pos
]
142 byteNum
:= strings
.LastIndex(text
, "\n")
144 byteNum
= pos
// On first line.
146 byteNum
++ // After the newline.
147 byteNum
= pos
- byteNum
149 lineNum
:= 1 + strings
.Count(text
, "\n")
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{}) {
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
) {
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
)
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
)
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
) {
196 if _
, ok
:= e
.(runtime
.Error
); ok
{
207 // startParse initializes the parser, using the lexer.
208 func (t
*Tree
) startParse(funcs
[]map[string]interface{}, lex
*lexer
, treeSet
map[string]*Tree
) {
211 t
.vars
= []string{"$"}
216 // stopParse terminates parsing.
217 func (t
*Tree
) stopParse() {
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
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
)
231 t
.startParse(funcs
, lex(t
.Name
, text
, leftDelim
, rightDelim
), treeSet
)
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
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) {
259 for _
, node
:= range n
.Nodes
{
260 if !IsEmptyTree(node
) {
268 return len(bytes
.TrimSpace(n
.Text
)) == 0
271 panic("unknown node: " + n
.String())
276 // parse is the top-level parser for a template, essentially the same
277 // as itemList except it also parses {{define}} actions.
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
{
284 if t
.nextNonSpace().typ
== itemDefine
{
285 newT
:= New("definition") // name will be updated once we know it.
287 newT
.ParseName
= t
.ParseName
288 newT
.startParse(t
.funcs
, t
.lex
, t
.treeSet
)
289 newT
.parseDefinition()
294 switch n
:= t
.textOrAction(); n
.Type() {
295 case nodeEnd
, nodeElse
:
296 t
.errorf("unexpected %s", n
)
303 // parseDefinition parses a {{define}} ... {{end}} template definition and
304 // installs the definition in t.treeSet. The "define" keyword has already
306 func (t
*Tree
) parseDefinition() {
307 const context
= "define clause"
308 name
:= t
.expectOneOf(itemString
, itemRawString
, context
)
310 t
.Name
, err
= strconv
.Unquote(name
.val
)
314 t
.expect(itemRightDelim
, context
)
316 t
.Root
, end
= t
.itemList()
317 if end
.Type() != nodeEnd
{
318 t
.errorf("unexpected %s in %s", end
, context
)
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()
332 case nodeEnd
, nodeElse
:
337 t
.errorf("unexpected EOF")
343 func (t
*Tree
) textOrAction() Node
{
344 switch token
:= t
.nextNonSpace(); token
.typ
{
346 return t
.newText(token
.pos
, token
.val
)
350 t
.unexpected(token
, "input")
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
{
363 return t
.blockControl()
365 return t
.elseControl()
367 return t
.endControl()
371 return t
.rangeControl()
373 return t
.templateControl()
375 return t
.withControl()
379 // Do not pop variables; they persist until "end".
380 return t
.newAction(token
.pos
, token
.line
, t
.pipeline("command"))
384 // declarations? command ('|' command)*
385 func (t
*Tree
) pipeline(context
string) (pipe
*PipeNode
) {
386 var decl
[]*VariableNode
387 token
:= t
.peekNonSpace()
389 // Are there declarations?
391 if v
:= t
.peekNonSpace(); v
.typ
== itemVariable
{
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
== ",") {
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 {
407 t
.errorf("too many declarations in %s", context
)
409 } else if tokenAfterVariable
.typ
== itemSpace
{
410 t
.backup3(v
, tokenAfterVariable
)
417 pipe
= t
.newPipeline(pos
, token
.line
, decl
)
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
{
427 case itemBool
, itemCharConstant
, itemComplex
, itemDot
, itemField
, itemIdentifier
,
428 itemNumber
, itemNil
, itemRawString
, itemString
, itemVariable
, itemLeftParen
:
430 pipe
.append(t
.command())
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
)
456 list
, next
= t
.itemList()
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}}
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.
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
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"))
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"))
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"))
511 // End keyword is past.
512 func (t
*Tree
) endControl() Node
{
513 return t
.newEnd(t
.expect(itemRightDelim
, "end").pos
)
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
)
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.
544 block
.ParseName
= t
.ParseName
545 block
.startParse(t
.funcs
, t
.lex
, t
.treeSet
)
547 block
.Root
, end
= block
.itemList()
548 if end
.Type() != nodeEnd
{
549 t
.errorf("unexpected %s in %s", end
, context
)
554 return t
.newTemplate(token
.pos
, token
.line
, name
, pipe
)
558 // {{template stringValue pipeline}}
559 // Template keyword is past. The name must be something that can evaluate
561 func (t
*Tree
) templateControl() Node
{
562 const context
= "template clause"
563 token
:= t
.nextNonSpace()
564 name
:= t
.parseTemplateName(token
, context
)
566 if t
.nextNonSpace().typ
!= itemRightDelim
{
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) {
576 case itemString
, itemRawString
:
577 s
, err
:= strconv
.Unquote(token
.val
)
583 t
.unexpected(token
, context
)
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
)
595 t
.peekNonSpace() // skip leading spaces.
596 operand
:= t
.operand()
600 switch token
:= t
.next(); token
.typ
{
604 t
.errorf("%s", token
.val
)
605 case itemRightDelim
, itemRightParen
:
609 t
.errorf("unexpected %s in operand", token
)
613 if len(cmd
.Args
) == 0 {
614 t
.errorf("empty command")
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
{
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.
641 node
= t
.newField(chain
.Position(), chain
.String())
643 node
= t
.newVariable(chain
.Position(), chain
.String())
644 case NodeBool
, NodeString
, NodeNumber
, NodeNil
, NodeDot
:
645 t
.errorf("unexpected . after term %q", node
.String())
654 // literal (number, string, nil, boolean)
655 // function (identifier)
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
{
665 t
.errorf("%s", token
.val
)
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
)
672 return t
.newDot(token
.pos
)
674 return t
.newNil(token
.pos
)
676 return t
.useVar(token
.pos
, token
.val
)
678 return t
.newField(token
.pos
, token
.val
)
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
)
688 pipe
:= t
.pipeline("parenthesized pipeline")
689 if token
:= t
.next(); token
.typ
!= itemRightParen
{
690 t
.errorf("unclosed right paren: unexpected %s", token
)
693 case itemString
, itemRawString
:
694 s
, err
:= strconv
.Unquote(token
.val
)
698 return t
.newString(token
.pos
, token
.val
, s
)
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
{
710 if funcMap
[name
] != nil {
717 // popVars trims the variable list to the specified length
718 func (t
*Tree
) popVars(n
int) {
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] {
731 t
.errorf("undefined variable %q", v
.Ident
[0])