OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [libgo/] [go/] [text/] [template/] [parse/] [parse.go] - Blame information for rev 747

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 747 jeremybenn
// 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
        "bytes"
11
        "fmt"
12
        "runtime"
13
        "strconv"
14
        "unicode"
15
)
16
 
17
// Tree is the representation of a single parsed template.
18
type Tree struct {
19
        Name string    // name of the template represented by the tree.
20
        Root *ListNode // top-level root of the 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
// Parse returns a map from template name to parse.Tree, created by parsing the
30
// templates described in the argument string. The top-level template will be
31
// given the specified name. If an error is encountered, parsing stops and an
32
// empty map is returned with the error.
33
func Parse(name, text, leftDelim, rightDelim string, funcs ...map[string]interface{}) (treeSet map[string]*Tree, err error) {
34
        treeSet = make(map[string]*Tree)
35
        _, err = New(name).Parse(text, leftDelim, rightDelim, treeSet, funcs...)
36
        return
37
}
38
 
39
// next returns the next token.
40
func (t *Tree) next() item {
41
        if t.peekCount > 0 {
42
                t.peekCount--
43
        } else {
44
                t.token[0] = t.lex.nextItem()
45
        }
46
        return t.token[t.peekCount]
47
}
48
 
49
// backup backs the input stream up one token.
50
func (t *Tree) backup() {
51
        t.peekCount++
52
}
53
 
54
// backup2 backs the input stream up two tokens
55
func (t *Tree) backup2(t1 item) {
56
        t.token[1] = t1
57
        t.peekCount = 2
58
}
59
 
60
// peek returns but does not consume the next token.
61
func (t *Tree) peek() item {
62
        if t.peekCount > 0 {
63
                return t.token[t.peekCount-1]
64
        }
65
        t.peekCount = 1
66
        t.token[0] = t.lex.nextItem()
67
        return t.token[0]
68
}
69
 
70
// Parsing.
71
 
72
// New allocates a new parse tree with the given name.
73
func New(name string, funcs ...map[string]interface{}) *Tree {
74
        return &Tree{
75
                Name:  name,
76
                funcs: funcs,
77
        }
78
}
79
 
80
// errorf formats the error and terminates processing.
81
func (t *Tree) errorf(format string, args ...interface{}) {
82
        t.Root = nil
83
        format = fmt.Sprintf("template: %s:%d: %s", t.Name, t.lex.lineNumber(), format)
84
        panic(fmt.Errorf(format, args...))
85
}
86
 
87
// error terminates processing.
88
func (t *Tree) error(err error) {
89
        t.errorf("%s", err)
90
}
91
 
92
// expect consumes the next token and guarantees it has the required type.
93
func (t *Tree) expect(expected itemType, context string) item {
94
        token := t.next()
95
        if token.typ != expected {
96
                t.errorf("expected %s in %s; got %s", expected, context, token)
97
        }
98
        return token
99
}
100
 
101
// expectEither consumes the next token and guarantees it has one of the required types.
102
func (t *Tree) expectOneOf(expected1, expected2 itemType, context string) item {
103
        token := t.next()
104
        if token.typ != expected1 && token.typ != expected2 {
105
                t.errorf("expected %s or %s in %s; got %s", expected1, expected2, context, token)
106
        }
107
        return token
108
}
109
 
110
// unexpected complains about the token and terminates processing.
111
func (t *Tree) unexpected(token item, context string) {
112
        t.errorf("unexpected %s in %s", token, context)
113
}
114
 
115
// recover is the handler that turns panics into returns from the top level of Parse.
116
func (t *Tree) recover(errp *error) {
117
        e := recover()
118
        if e != nil {
119
                if _, ok := e.(runtime.Error); ok {
120
                        panic(e)
121
                }
122
                if t != nil {
123
                        t.stopParse()
124
                }
125
                *errp = e.(error)
126
        }
127
        return
128
}
129
 
130
// startParse initializes the parser, using the lexer.
131
func (t *Tree) startParse(funcs []map[string]interface{}, lex *lexer) {
132
        t.Root = nil
133
        t.lex = lex
134
        t.vars = []string{"$"}
135
        t.funcs = funcs
136
}
137
 
138
// stopParse terminates parsing.
139
func (t *Tree) stopParse() {
140
        t.lex = nil
141
        t.vars = nil
142
        t.funcs = nil
143
}
144
 
145
// atEOF returns true if, possibly after spaces, we're at EOF.
146
func (t *Tree) atEOF() bool {
147
        for {
148
                token := t.peek()
149
                switch token.typ {
150
                case itemEOF:
151
                        return true
152
                case itemText:
153
                        for _, r := range token.val {
154
                                if !unicode.IsSpace(r) {
155
                                        return false
156
                                }
157
                        }
158
                        t.next() // skip spaces.
159
                        continue
160
                }
161
                break
162
        }
163
        return false
164
}
165
 
166
// Parse parses the template definition string to construct a representation of
167
// the template for execution. If either action delimiter string is empty, the
168
// default ("{{" or "}}") is used. Embedded template definitions are added to
169
// the treeSet map.
170
func (t *Tree) Parse(s, leftDelim, rightDelim string, treeSet map[string]*Tree, funcs ...map[string]interface{}) (tree *Tree, err error) {
171
        defer t.recover(&err)
172
        t.startParse(funcs, lex(t.Name, s, leftDelim, rightDelim))
173
        t.parse(treeSet)
174
        t.add(treeSet)
175
        t.stopParse()
176
        return t, nil
177
}
178
 
179
// add adds tree to the treeSet.
180
func (t *Tree) add(treeSet map[string]*Tree) {
181
        tree := treeSet[t.Name]
182
        if tree == nil || IsEmptyTree(tree.Root) {
183
                treeSet[t.Name] = t
184
                return
185
        }
186
        if !IsEmptyTree(t.Root) {
187
                t.errorf("template: multiple definition of template %q", t.Name)
188
        }
189
}
190
 
191
// IsEmptyTree reports whether this tree (node) is empty of everything but space.
192
func IsEmptyTree(n Node) bool {
193
        switch n := n.(type) {
194
        case *ActionNode:
195
        case *IfNode:
196
        case *ListNode:
197
                for _, node := range n.Nodes {
198
                        if !IsEmptyTree(node) {
199
                                return false
200
                        }
201
                }
202
                return true
203
        case *RangeNode:
204
        case *TemplateNode:
205
        case *TextNode:
206
                return len(bytes.TrimSpace(n.Text)) == 0
207
        case *WithNode:
208
        default:
209
                panic("unknown node: " + n.String())
210
        }
211
        return false
212
}
213
 
214
// parse is the top-level parser for a template, essentially the same
215
// as itemList except it also parses {{define}} actions.
216
// It runs to EOF.
217
func (t *Tree) parse(treeSet map[string]*Tree) (next Node) {
218
        t.Root = newList()
219
        for t.peek().typ != itemEOF {
220
                if t.peek().typ == itemLeftDelim {
221
                        delim := t.next()
222
                        if t.next().typ == itemDefine {
223
                                newT := New("definition") // name will be updated once we know it.
224
                                newT.startParse(t.funcs, t.lex)
225
                                newT.parseDefinition(treeSet)
226
                                continue
227
                        }
228
                        t.backup2(delim)
229
                }
230
                n := t.textOrAction()
231
                if n.Type() == nodeEnd {
232
                        t.errorf("unexpected %s", n)
233
                }
234
                t.Root.append(n)
235
        }
236
        return nil
237
}
238
 
239
// parseDefinition parses a {{define}} ...  {{end}} template definition and
240
// installs the definition in the treeSet map.  The "define" keyword has already
241
// been scanned.
242
func (t *Tree) parseDefinition(treeSet map[string]*Tree) {
243
        const context = "define clause"
244
        name := t.expectOneOf(itemString, itemRawString, context)
245
        var err error
246
        t.Name, err = strconv.Unquote(name.val)
247
        if err != nil {
248
                t.error(err)
249
        }
250
        t.expect(itemRightDelim, context)
251
        var end Node
252
        t.Root, end = t.itemList()
253
        if end.Type() != nodeEnd {
254
                t.errorf("unexpected %s in %s", end, context)
255
        }
256
        t.stopParse()
257
        t.add(treeSet)
258
}
259
 
260
// itemList:
261
//      textOrAction*
262
// Terminates at {{end}} or {{else}}, returned separately.
263
func (t *Tree) itemList() (list *ListNode, next Node) {
264
        list = newList()
265
        for t.peek().typ != itemEOF {
266
                n := t.textOrAction()
267
                switch n.Type() {
268
                case nodeEnd, nodeElse:
269
                        return list, n
270
                }
271
                list.append(n)
272
        }
273
        t.errorf("unexpected EOF")
274
        return
275
}
276
 
277
// textOrAction:
278
//      text | action
279
func (t *Tree) textOrAction() Node {
280
        switch token := t.next(); token.typ {
281
        case itemText:
282
                return newText(token.val)
283
        case itemLeftDelim:
284
                return t.action()
285
        default:
286
                t.unexpected(token, "input")
287
        }
288
        return nil
289
}
290
 
291
// Action:
292
//      control
293
//      command ("|" command)*
294
// Left delim is past. Now get actions.
295
// First word could be a keyword such as range.
296
func (t *Tree) action() (n Node) {
297
        switch token := t.next(); token.typ {
298
        case itemElse:
299
                return t.elseControl()
300
        case itemEnd:
301
                return t.endControl()
302
        case itemIf:
303
                return t.ifControl()
304
        case itemRange:
305
                return t.rangeControl()
306
        case itemTemplate:
307
                return t.templateControl()
308
        case itemWith:
309
                return t.withControl()
310
        }
311
        t.backup()
312
        // Do not pop variables; they persist until "end".
313
        return newAction(t.lex.lineNumber(), t.pipeline("command"))
314
}
315
 
316
// Pipeline:
317
//      field or command
318
//      pipeline "|" pipeline
319
func (t *Tree) pipeline(context string) (pipe *PipeNode) {
320
        var decl []*VariableNode
321
        // Are there declarations?
322
        for {
323
                if v := t.peek(); v.typ == itemVariable {
324
                        t.next()
325
                        if next := t.peek(); next.typ == itemColonEquals || next.typ == itemChar {
326
                                t.next()
327
                                variable := newVariable(v.val)
328
                                if len(variable.Ident) != 1 {
329
                                        t.errorf("illegal variable in declaration: %s", v.val)
330
                                }
331
                                decl = append(decl, variable)
332
                                t.vars = append(t.vars, v.val)
333
                                if next.typ == itemChar && next.val == "," {
334
                                        if context == "range" && len(decl) < 2 {
335
                                                continue
336
                                        }
337
                                        t.errorf("too many declarations in %s", context)
338
                                }
339
                        } else {
340
                                t.backup2(v)
341
                        }
342
                }
343
                break
344
        }
345
        pipe = newPipeline(t.lex.lineNumber(), decl)
346
        for {
347
                switch token := t.next(); token.typ {
348
                case itemRightDelim:
349
                        if len(pipe.Cmds) == 0 {
350
                                t.errorf("missing value for %s", context)
351
                        }
352
                        return
353
                case itemBool, itemCharConstant, itemComplex, itemDot, itemField, itemIdentifier,
354
                        itemVariable, itemNumber, itemRawString, itemString:
355
                        t.backup()
356
                        pipe.append(t.command())
357
                default:
358
                        t.unexpected(token, context)
359
                }
360
        }
361
        return
362
}
363
 
364
func (t *Tree) parseControl(context string) (lineNum int, pipe *PipeNode, list, elseList *ListNode) {
365
        lineNum = t.lex.lineNumber()
366
        defer t.popVars(len(t.vars))
367
        pipe = t.pipeline(context)
368
        var next Node
369
        list, next = t.itemList()
370
        switch next.Type() {
371
        case nodeEnd: //done
372
        case nodeElse:
373
                elseList, next = t.itemList()
374
                if next.Type() != nodeEnd {
375
                        t.errorf("expected end; found %s", next)
376
                }
377
                elseList = elseList
378
        }
379
        return lineNum, pipe, list, elseList
380
}
381
 
382
// If:
383
//      {{if pipeline}} itemList {{end}}
384
//      {{if pipeline}} itemList {{else}} itemList {{end}}
385
// If keyword is past.
386
func (t *Tree) ifControl() Node {
387
        return newIf(t.parseControl("if"))
388
}
389
 
390
// Range:
391
//      {{range pipeline}} itemList {{end}}
392
//      {{range pipeline}} itemList {{else}} itemList {{end}}
393
// Range keyword is past.
394
func (t *Tree) rangeControl() Node {
395
        return newRange(t.parseControl("range"))
396
}
397
 
398
// With:
399
//      {{with pipeline}} itemList {{end}}
400
//      {{with pipeline}} itemList {{else}} itemList {{end}}
401
// If keyword is past.
402
func (t *Tree) withControl() Node {
403
        return newWith(t.parseControl("with"))
404
}
405
 
406
// End:
407
//      {{end}}
408
// End keyword is past.
409
func (t *Tree) endControl() Node {
410
        t.expect(itemRightDelim, "end")
411
        return newEnd()
412
}
413
 
414
// Else:
415
//      {{else}}
416
// Else keyword is past.
417
func (t *Tree) elseControl() Node {
418
        t.expect(itemRightDelim, "else")
419
        return newElse(t.lex.lineNumber())
420
}
421
 
422
// Template:
423
//      {{template stringValue pipeline}}
424
// Template keyword is past.  The name must be something that can evaluate
425
// to a string.
426
func (t *Tree) templateControl() Node {
427
        var name string
428
        switch token := t.next(); token.typ {
429
        case itemString, itemRawString:
430
                s, err := strconv.Unquote(token.val)
431
                if err != nil {
432
                        t.error(err)
433
                }
434
                name = s
435
        default:
436
                t.unexpected(token, "template invocation")
437
        }
438
        var pipe *PipeNode
439
        if t.next().typ != itemRightDelim {
440
                t.backup()
441
                // Do not pop variables; they persist until "end".
442
                pipe = t.pipeline("template")
443
        }
444
        return newTemplate(t.lex.lineNumber(), name, pipe)
445
}
446
 
447
// command:
448
// space-separated arguments up to a pipeline character or right delimiter.
449
// we consume the pipe character but leave the right delim to terminate the action.
450
func (t *Tree) command() *CommandNode {
451
        cmd := newCommand()
452
Loop:
453
        for {
454
                switch token := t.next(); token.typ {
455
                case itemRightDelim:
456
                        t.backup()
457
                        break Loop
458
                case itemPipe:
459
                        break Loop
460
                case itemError:
461
                        t.errorf("%s", token.val)
462
                case itemIdentifier:
463
                        if !t.hasFunction(token.val) {
464
                                t.errorf("function %q not defined", token.val)
465
                        }
466
                        cmd.append(NewIdentifier(token.val))
467
                case itemDot:
468
                        cmd.append(newDot())
469
                case itemVariable:
470
                        cmd.append(t.useVar(token.val))
471
                case itemField:
472
                        cmd.append(newField(token.val))
473
                case itemBool:
474
                        cmd.append(newBool(token.val == "true"))
475
                case itemCharConstant, itemComplex, itemNumber:
476
                        number, err := newNumber(token.val, token.typ)
477
                        if err != nil {
478
                                t.error(err)
479
                        }
480
                        cmd.append(number)
481
                case itemString, itemRawString:
482
                        s, err := strconv.Unquote(token.val)
483
                        if err != nil {
484
                                t.error(err)
485
                        }
486
                        cmd.append(newString(token.val, s))
487
                default:
488
                        t.unexpected(token, "command")
489
                }
490
        }
491
        if len(cmd.Args) == 0 {
492
                t.errorf("empty command")
493
        }
494
        return cmd
495
}
496
 
497
// hasFunction reports if a function name exists in the Tree's maps.
498
func (t *Tree) hasFunction(name string) bool {
499
        for _, funcMap := range t.funcs {
500
                if funcMap == nil {
501
                        continue
502
                }
503
                if funcMap[name] != nil {
504
                        return true
505
                }
506
        }
507
        return false
508
}
509
 
510
// popVars trims the variable list to the specified length
511
func (t *Tree) popVars(n int) {
512
        t.vars = t.vars[:n]
513
}
514
 
515
// useVar returns a node for a variable reference. It errors if the
516
// variable is not defined.
517
func (t *Tree) useVar(name string) Node {
518
        v := newVariable(name)
519
        for _, varName := range t.vars {
520
                if varName == v.Ident[0] {
521
                        return v
522
                }
523
        }
524
        t.errorf("undefined variable %q", v.Ident[0])
525
        return nil
526
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.