6918074664e9e9e0f146ef90034e45d5ab836159
[platform/upstream/gcc.git] / libgo / go / 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         "os"
12         "runtime"
13         "strconv"
14         "unicode"
15 )
16
17 // Tree is the representation of a parsed template.
18 type Tree struct {
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{}
23         lex       *lexer
24         token     [2]item // two-token lookahead for parser.
25         peekCount int
26         vars      []string // variables defined at the moment.
27 }
28
29 // next returns the next token.
30 func (t *Tree) next() item {
31         if t.peekCount > 0 {
32                 t.peekCount--
33         } else {
34                 t.token[0] = t.lex.nextItem()
35         }
36         return t.token[t.peekCount]
37 }
38
39 // backup backs the input stream up one token.
40 func (t *Tree) backup() {
41         t.peekCount++
42 }
43
44 // backup2 backs the input stream up two tokens
45 func (t *Tree) backup2(t1 item) {
46         t.token[1] = t1
47         t.peekCount = 2
48 }
49
50 // peek returns but does not consume the next token.
51 func (t *Tree) peek() item {
52         if t.peekCount > 0 {
53                 return t.token[t.peekCount-1]
54         }
55         t.peekCount = 1
56         t.token[0] = t.lex.nextItem()
57         return t.token[0]
58 }
59
60 // Parsing.
61
62 // New allocates a new template with the given name.
63 func New(name string, funcs ...map[string]interface{}) *Tree {
64         return &Tree{
65                 Name:  name,
66                 funcs: funcs,
67         }
68 }
69
70 // errorf formats the error and terminates processing.
71 func (t *Tree) errorf(format string, args ...interface{}) {
72         t.Root = nil
73         format = fmt.Sprintf("template: %s:%d: %s", t.Name, t.lex.lineNumber(), format)
74         panic(fmt.Errorf(format, args...))
75 }
76
77 // error terminates processing.
78 func (t *Tree) error(err os.Error) {
79         t.errorf("%s", err)
80 }
81
82 // expect consumes the next token and guarantees it has the required type.
83 func (t *Tree) expect(expected itemType, context string) item {
84         token := t.next()
85         if token.typ != expected {
86                 t.errorf("expected %s in %s; got %s", expected, context, token)
87         }
88         return token
89 }
90
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)
94 }
95
96 // recover is the handler that turns panics into returns from the top level of Parse.
97 func (t *Tree) recover(errp *os.Error) {
98         e := recover()
99         if e != nil {
100                 if _, ok := e.(runtime.Error); ok {
101                         panic(e)
102                 }
103                 if t != nil {
104                         t.stopParse()
105                 }
106                 *errp = e.(os.Error)
107         }
108         return
109 }
110
111 // startParse starts the template parsing from the lexer.
112 func (t *Tree) startParse(funcs []map[string]interface{}, lex *lexer) {
113         t.Root = nil
114         t.lex = lex
115         t.vars = []string{"$"}
116         t.funcs = funcs
117 }
118
119 // stopParse terminates parsing.
120 func (t *Tree) stopParse() {
121         t.lex = nil
122         t.vars = nil
123         t.funcs = nil
124 }
125
126 // atEOF returns true if, possibly after spaces, we're at EOF.
127 func (t *Tree) atEOF() bool {
128         for {
129                 token := t.peek()
130                 switch token.typ {
131                 case itemEOF:
132                         return true
133                 case itemText:
134                         for _, r := range token.val {
135                                 if !unicode.IsSpace(r) {
136                                         return false
137                                 }
138                         }
139                         t.next() // skip spaces.
140                         continue
141                 }
142                 break
143         }
144         return false
145 }
146
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))
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 }