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. The grammar is defined
6 // in the documents for the template package.
17 // Tree is the representation of a parsed template.
19 Name string // Name is the name of the template.
20 Root *ListNode // Root is the top-level root of the parse tree.
21 // Parsing only; cleared after parse.
22 funcs []map[string]interface{}
24 token [2]item // two-token lookahead for parser.
26 vars []string // variables defined at the moment.
29 // next returns the next token.
30 func (t *Tree) next() item {
34 t.token[0] = t.lex.nextItem()
36 return t.token[t.peekCount]
39 // backup backs the input stream up one token.
40 func (t *Tree) backup() {
44 // backup2 backs the input stream up two tokens
45 func (t *Tree) backup2(t1 item) {
50 // peek returns but does not consume the next token.
51 func (t *Tree) peek() item {
53 return t.token[t.peekCount-1]
56 t.token[0] = t.lex.nextItem()
62 // New allocates a new template with the given name.
63 func New(name string, funcs ...map[string]interface{}) *Tree {
70 // errorf formats the error and terminates processing.
71 func (t *Tree) errorf(format string, args ...interface{}) {
73 format = fmt.Sprintf("template: %s:%d: %s", t.Name, t.lex.lineNumber(), format)
74 panic(fmt.Errorf(format, args...))
77 // error terminates processing.
78 func (t *Tree) error(err os.Error) {
82 // expect consumes the next token and guarantees it has the required type.
83 func (t *Tree) expect(expected itemType, context string) item {
85 if token.typ != expected {
86 t.errorf("expected %s in %s; got %s", expected, context, token)
91 // unexpected complains about the token and terminates processing.
92 func (t *Tree) unexpected(token item, context string) {
93 t.errorf("unexpected %s in %s", token, context)
96 // recover is the handler that turns panics into returns from the top level of Parse.
97 func (t *Tree) recover(errp *os.Error) {
100 if _, ok := e.(runtime.Error); ok {
111 // startParse starts the template parsing from the lexer.
112 func (t *Tree) startParse(funcs []map[string]interface{}, lex *lexer) {
115 t.vars = []string{"$"}
119 // stopParse terminates parsing.
120 func (t *Tree) stopParse() {
126 // atEOF returns true if, possibly after spaces, we're at EOF.
127 func (t *Tree) atEOF() bool {
134 for _, r := range token.val {
135 if !unicode.IsSpace(r) {
139 t.next() // skip spaces.
147 // Parse parses the template definition string to construct an internal
148 // representation of the template for execution.
149 func (t *Tree) Parse(s string, funcs ...map[string]interface{}) (tree *Tree, err os.Error) {
150 defer t.recover(&err)
151 t.startParse(funcs, lex(t.Name, s))
157 // parse is the helper for Parse.
158 // It triggers an error if we expect EOF but don't reach it.
159 func (t *Tree) parse(toEOF bool) (next Node) {
160 t.Root, next = t.itemList(true)
161 if toEOF && next != nil {
162 t.errorf("unexpected %s", next)
169 // Terminates at EOF and at {{end}} or {{else}}, which is returned separately.
170 // The toEOF flag tells whether we expect to reach EOF.
171 func (t *Tree) itemList(toEOF bool) (list *ListNode, next Node) {
173 for t.peek().typ != itemEOF {
174 n := t.textOrAction()
176 case nodeEnd, nodeElse:
182 t.unexpected(t.next(), "input")
189 func (t *Tree) textOrAction() Node {
190 switch token := t.next(); token.typ {
192 return newText(token.val)
196 t.unexpected(token, "input")
203 // command ("|" command)*
204 // Left delim is past. Now get actions.
205 // First word could be a keyword such as range.
206 func (t *Tree) action() (n Node) {
207 switch token := t.next(); token.typ {
209 return t.elseControl()
211 return t.endControl()
215 return t.rangeControl()
217 return t.templateControl()
219 return t.withControl()
222 // Do not pop variables; they persist until "end".
223 return newAction(t.lex.lineNumber(), t.pipeline("command"))
228 // pipeline "|" pipeline
229 func (t *Tree) pipeline(context string) (pipe *PipeNode) {
230 var decl []*VariableNode
231 // Are there declarations?
233 if v := t.peek(); v.typ == itemVariable {
235 if next := t.peek(); next.typ == itemColonEquals || next.typ == itemChar {
237 variable := newVariable(v.val)
238 if len(variable.Ident) != 1 {
239 t.errorf("illegal variable in declaration: %s", v.val)
241 decl = append(decl, variable)
242 t.vars = append(t.vars, v.val)
243 if next.typ == itemChar && next.val == "," {
244 if context == "range" && len(decl) < 2 {
247 t.errorf("too many declarations in %s", context)
255 pipe = newPipeline(t.lex.lineNumber(), decl)
257 switch token := t.next(); token.typ {
259 if len(pipe.Cmds) == 0 {
260 t.errorf("missing value for %s", context)
263 case itemBool, itemCharConstant, itemComplex, itemDot, itemField, itemIdentifier,
264 itemVariable, itemNumber, itemRawString, itemString:
266 pipe.append(t.command())
268 t.unexpected(token, context)
274 func (t *Tree) parseControl(context string) (lineNum int, pipe *PipeNode, list, elseList *ListNode) {
275 lineNum = t.lex.lineNumber()
276 defer t.popVars(len(t.vars))
277 pipe = t.pipeline(context)
279 list, next = t.itemList(false)
283 elseList, next = t.itemList(false)
284 if next.Type() != nodeEnd {
285 t.errorf("expected end; found %s", next)
289 return lineNum, pipe, list, elseList
293 // {{if pipeline}} itemList {{end}}
294 // {{if pipeline}} itemList {{else}} itemList {{end}}
295 // If keyword is past.
296 func (t *Tree) ifControl() Node {
297 return newIf(t.parseControl("if"))
301 // {{range pipeline}} itemList {{end}}
302 // {{range pipeline}} itemList {{else}} itemList {{end}}
303 // Range keyword is past.
304 func (t *Tree) rangeControl() Node {
305 return newRange(t.parseControl("range"))
309 // {{with pipeline}} itemList {{end}}
310 // {{with pipeline}} itemList {{else}} itemList {{end}}
311 // If keyword is past.
312 func (t *Tree) withControl() Node {
313 return newWith(t.parseControl("with"))
318 // End keyword is past.
319 func (t *Tree) endControl() Node {
320 t.expect(itemRightDelim, "end")
326 // Else keyword is past.
327 func (t *Tree) elseControl() Node {
328 t.expect(itemRightDelim, "else")
329 return newElse(t.lex.lineNumber())
333 // {{template stringValue pipeline}}
334 // Template keyword is past. The name must be something that can evaluate
336 func (t *Tree) templateControl() Node {
338 switch token := t.next(); token.typ {
339 case itemString, itemRawString:
340 s, err := strconv.Unquote(token.val)
346 t.unexpected(token, "template invocation")
349 if t.next().typ != itemRightDelim {
351 // Do not pop variables; they persist until "end".
352 pipe = t.pipeline("template")
354 return newTemplate(t.lex.lineNumber(), name, pipe)
358 // space-separated arguments up to a pipeline character or right delimiter.
359 // we consume the pipe character but leave the right delim to terminate the action.
360 func (t *Tree) command() *CommandNode {
364 switch token := t.next(); token.typ {
371 t.errorf("%s", token.val)
373 if !t.hasFunction(token.val) {
374 t.errorf("function %q not defined", token.val)
376 cmd.append(NewIdentifier(token.val))
380 cmd.append(t.useVar(token.val))
382 cmd.append(newField(token.val))
384 cmd.append(newBool(token.val == "true"))
385 case itemCharConstant, itemComplex, itemNumber:
386 number, err := newNumber(token.val, token.typ)
391 case itemString, itemRawString:
392 s, err := strconv.Unquote(token.val)
396 cmd.append(newString(token.val, s))
398 t.unexpected(token, "command")
401 if len(cmd.Args) == 0 {
402 t.errorf("empty command")
407 // hasFunction reports if a function name exists in the Tree's maps.
408 func (t *Tree) hasFunction(name string) bool {
409 for _, funcMap := range t.funcs {
413 if funcMap[name] != nil {
420 // popVars trims the variable list to the specified length
421 func (t *Tree) popVars(n int) {
425 // useVar returns a node for a variable reference. It errors if the
426 // variable is not defined.
427 func (t *Tree) useVar(name string) Node {
428 v := newVariable(name)
429 for _, varName := range t.vars {
430 if varName == v.Ident[0] {
434 t.errorf("undefined variable %q", v.Ident[0])