OSDN Git Service

libgo: Update to weekly 2011-11-09.
[pf3gnuchains/gcc-fork.git] / libgo / go / text / template / parse / parse.go
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.  The grammar is defined
6 // in the documents for the template package.
7 package parse
8
9 import (
10         "fmt"
11         "runtime"
12         "strconv"
13         "unicode"
14 )
15
16 // Tree is the representation of a parsed template.
17 type Tree struct {
18         Name string    // Name is the name of the template.
19         Root *ListNode // Root is the top-level root of the parse tree.
20         // Parsing only; cleared after parse.
21         funcs     []map[string]interface{}
22         lex       *lexer
23         token     [2]item // two-token lookahead for parser.
24         peekCount int
25         vars      []string // variables defined at the moment.
26 }
27
28 // next returns the next token.
29 func (t *Tree) next() item {
30         if t.peekCount > 0 {
31                 t.peekCount--
32         } else {
33                 t.token[0] = t.lex.nextItem()
34         }
35         return t.token[t.peekCount]
36 }
37
38 // backup backs the input stream up one token.
39 func (t *Tree) backup() {
40         t.peekCount++
41 }
42
43 // backup2 backs the input stream up two tokens
44 func (t *Tree) backup2(t1 item) {
45         t.token[1] = t1
46         t.peekCount = 2
47 }
48
49 // peek returns but does not consume the next token.
50 func (t *Tree) peek() item {
51         if t.peekCount > 0 {
52                 return t.token[t.peekCount-1]
53         }
54         t.peekCount = 1
55         t.token[0] = t.lex.nextItem()
56         return t.token[0]
57 }
58
59 // Parsing.
60
61 // New allocates a new template with the given name.
62 func New(name string, funcs ...map[string]interface{}) *Tree {
63         return &Tree{
64                 Name:  name,
65                 funcs: funcs,
66         }
67 }
68
69 // errorf formats the error and terminates processing.
70 func (t *Tree) errorf(format string, args ...interface{}) {
71         t.Root = nil
72         format = fmt.Sprintf("template: %s:%d: %s", t.Name, t.lex.lineNumber(), format)
73         panic(fmt.Errorf(format, args...))
74 }
75
76 // error terminates processing.
77 func (t *Tree) error(err error) {
78         t.errorf("%s", err)
79 }
80
81 // expect consumes the next token and guarantees it has the required type.
82 func (t *Tree) expect(expected itemType, context string) item {
83         token := t.next()
84         if token.typ != expected {
85                 t.errorf("expected %s in %s; got %s", expected, context, token)
86         }
87         return token
88 }
89
90 // unexpected complains about the token and terminates processing.
91 func (t *Tree) unexpected(token item, context string) {
92         t.errorf("unexpected %s in %s", token, context)
93 }
94
95 // recover is the handler that turns panics into returns from the top level of Parse.
96 func (t *Tree) recover(errp *error) {
97         e := recover()
98         if e != nil {
99                 if _, ok := e.(runtime.Error); ok {
100                         panic(e)
101                 }
102                 if t != nil {
103                         t.stopParse()
104                 }
105                 *errp = e.(error)
106         }
107         return
108 }
109
110 // startParse starts the template parsing from the lexer.
111 func (t *Tree) startParse(funcs []map[string]interface{}, lex *lexer) {
112         t.Root = nil
113         t.lex = lex
114         t.vars = []string{"$"}
115         t.funcs = funcs
116 }
117
118 // stopParse terminates parsing.
119 func (t *Tree) stopParse() {
120         t.lex = nil
121         t.vars = nil
122         t.funcs = nil
123 }
124
125 // atEOF returns true if, possibly after spaces, we're at EOF.
126 func (t *Tree) atEOF() bool {
127         for {
128                 token := t.peek()
129                 switch token.typ {
130                 case itemEOF:
131                         return true
132                 case itemText:
133                         for _, r := range token.val {
134                                 if !unicode.IsSpace(r) {
135                                         return false
136                                 }
137                         }
138                         t.next() // skip spaces.
139                         continue
140                 }
141                 break
142         }
143         return false
144 }
145
146 // Parse parses the template definition string to construct an internal
147 // representation of the template for execution. If either action delimiter
148 // string is empty, the default ("{{" or "}}") is used.
149 func (t *Tree) Parse(s, leftDelim, rightDelim string, funcs ...map[string]interface{}) (tree *Tree, err error) {
150         defer t.recover(&err)
151         t.startParse(funcs, lex(t.Name, s, leftDelim, rightDelim))
152         t.parse(true)
153         t.stopParse()
154         return t, nil
155 }
156
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)
163         }
164         return next
165 }
166
167 // itemList:
168 //      textOrAction*
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) {
172         list = newList()
173         for t.peek().typ != itemEOF {
174                 n := t.textOrAction()
175                 switch n.Type() {
176                 case nodeEnd, nodeElse:
177                         return list, n
178                 }
179                 list.append(n)
180         }
181         if !toEOF {
182                 t.unexpected(t.next(), "input")
183         }
184         return list, nil
185 }
186
187 // textOrAction:
188 //      text | action
189 func (t *Tree) textOrAction() Node {
190         switch token := t.next(); token.typ {
191         case itemText:
192                 return newText(token.val)
193         case itemLeftDelim:
194                 return t.action()
195         default:
196                 t.unexpected(token, "input")
197         }
198         return nil
199 }
200
201 // Action:
202 //      control
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 {
208         case itemElse:
209                 return t.elseControl()
210         case itemEnd:
211                 return t.endControl()
212         case itemIf:
213                 return t.ifControl()
214         case itemRange:
215                 return t.rangeControl()
216         case itemTemplate:
217                 return t.templateControl()
218         case itemWith:
219                 return t.withControl()
220         }
221         t.backup()
222         // Do not pop variables; they persist until "end".
223         return newAction(t.lex.lineNumber(), t.pipeline("command"))
224 }
225
226 // Pipeline:
227 //      field or command
228 //      pipeline "|" pipeline
229 func (t *Tree) pipeline(context string) (pipe *PipeNode) {
230         var decl []*VariableNode
231         // Are there declarations?
232         for {
233                 if v := t.peek(); v.typ == itemVariable {
234                         t.next()
235                         if next := t.peek(); next.typ == itemColonEquals || next.typ == itemChar {
236                                 t.next()
237                                 variable := newVariable(v.val)
238                                 if len(variable.Ident) != 1 {
239                                         t.errorf("illegal variable in declaration: %s", v.val)
240                                 }
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 {
245                                                 continue
246                                         }
247                                         t.errorf("too many declarations in %s", context)
248                                 }
249                         } else {
250                                 t.backup2(v)
251                         }
252                 }
253                 break
254         }
255         pipe = newPipeline(t.lex.lineNumber(), decl)
256         for {
257                 switch token := t.next(); token.typ {
258                 case itemRightDelim:
259                         if len(pipe.Cmds) == 0 {
260                                 t.errorf("missing value for %s", context)
261                         }
262                         return
263                 case itemBool, itemCharConstant, itemComplex, itemDot, itemField, itemIdentifier,
264                         itemVariable, itemNumber, itemRawString, itemString:
265                         t.backup()
266                         pipe.append(t.command())
267                 default:
268                         t.unexpected(token, context)
269                 }
270         }
271         return
272 }
273
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)
278         var next Node
279         list, next = t.itemList(false)
280         switch next.Type() {
281         case nodeEnd: //done
282         case nodeElse:
283                 elseList, next = t.itemList(false)
284                 if next.Type() != nodeEnd {
285                         t.errorf("expected end; found %s", next)
286                 }
287                 elseList = elseList
288         }
289         return lineNum, pipe, list, elseList
290 }
291
292 // If:
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"))
298 }
299
300 // Range:
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"))
306 }
307
308 // With:
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"))
314 }
315
316 // End:
317 //      {{end}}
318 // End keyword is past.
319 func (t *Tree) endControl() Node {
320         t.expect(itemRightDelim, "end")
321         return newEnd()
322 }
323
324 // Else:
325 //      {{else}}
326 // Else keyword is past.
327 func (t *Tree) elseControl() Node {
328         t.expect(itemRightDelim, "else")
329         return newElse(t.lex.lineNumber())
330 }
331
332 // Template:
333 //      {{template stringValue pipeline}}
334 // Template keyword is past.  The name must be something that can evaluate
335 // to a string.
336 func (t *Tree) templateControl() Node {
337         var name string
338         switch token := t.next(); token.typ {
339         case itemString, itemRawString:
340                 s, err := strconv.Unquote(token.val)
341                 if err != nil {
342                         t.error(err)
343                 }
344                 name = s
345         default:
346                 t.unexpected(token, "template invocation")
347         }
348         var pipe *PipeNode
349         if t.next().typ != itemRightDelim {
350                 t.backup()
351                 // Do not pop variables; they persist until "end".
352                 pipe = t.pipeline("template")
353         }
354         return newTemplate(t.lex.lineNumber(), name, pipe)
355 }
356
357 // command:
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 {
361         cmd := newCommand()
362 Loop:
363         for {
364                 switch token := t.next(); token.typ {
365                 case itemRightDelim:
366                         t.backup()
367                         break Loop
368                 case itemPipe:
369                         break Loop
370                 case itemError:
371                         t.errorf("%s", token.val)
372                 case itemIdentifier:
373                         if !t.hasFunction(token.val) {
374                                 t.errorf("function %q not defined", token.val)
375                         }
376                         cmd.append(NewIdentifier(token.val))
377                 case itemDot:
378                         cmd.append(newDot())
379                 case itemVariable:
380                         cmd.append(t.useVar(token.val))
381                 case itemField:
382                         cmd.append(newField(token.val))
383                 case itemBool:
384                         cmd.append(newBool(token.val == "true"))
385                 case itemCharConstant, itemComplex, itemNumber:
386                         number, err := newNumber(token.val, token.typ)
387                         if err != nil {
388                                 t.error(err)
389                         }
390                         cmd.append(number)
391                 case itemString, itemRawString:
392                         s, err := strconv.Unquote(token.val)
393                         if err != nil {
394                                 t.error(err)
395                         }
396                         cmd.append(newString(token.val, s))
397                 default:
398                         t.unexpected(token, "command")
399                 }
400         }
401         if len(cmd.Args) == 0 {
402                 t.errorf("empty command")
403         }
404         return cmd
405 }
406
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 {
410                 if funcMap == nil {
411                         continue
412                 }
413                 if funcMap[name] != nil {
414                         return true
415                 }
416         }
417         return false
418 }
419
420 // popVars trims the variable list to the specified length
421 func (t *Tree) popVars(n int) {
422         t.vars = t.vars[:n]
423 }
424
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] {
431                         return v
432                 }
433         }
434         t.errorf("undefined variable %q", v.Ident[0])
435         return nil
436 }