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

Subversion Repositories openrisc

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

Go to most recent revision | 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 template
6
 
7
import (
8
        "bytes"
9
        "fmt"
10
        "io"
11
        "net/url"
12
        "reflect"
13
        "strings"
14
        "unicode"
15
        "unicode/utf8"
16
)
17
 
18
// FuncMap is the type of the map defining the mapping from names to functions.
19
// Each function must have either a single return value, or two return values of
20
// which the second has type error. In that case, if the second (error)
21
// argument evaluates to non-nil during execution, execution terminates and
22
// Execute returns that error.
23
type FuncMap map[string]interface{}
24
 
25
var builtins = FuncMap{
26
        "and":      and,
27
        "html":     HTMLEscaper,
28
        "index":    index,
29
        "js":       JSEscaper,
30
        "len":      length,
31
        "not":      not,
32
        "or":       or,
33
        "print":    fmt.Sprint,
34
        "printf":   fmt.Sprintf,
35
        "println":  fmt.Sprintln,
36
        "urlquery": URLQueryEscaper,
37
}
38
 
39
var builtinFuncs = createValueFuncs(builtins)
40
 
41
// createValueFuncs turns a FuncMap into a map[string]reflect.Value
42
func createValueFuncs(funcMap FuncMap) map[string]reflect.Value {
43
        m := make(map[string]reflect.Value)
44
        addValueFuncs(m, funcMap)
45
        return m
46
}
47
 
48
// addValueFuncs adds to values the functions in funcs, converting them to reflect.Values.
49
func addValueFuncs(out map[string]reflect.Value, in FuncMap) {
50
        for name, fn := range in {
51
                v := reflect.ValueOf(fn)
52
                if v.Kind() != reflect.Func {
53
                        panic("value for " + name + " not a function")
54
                }
55
                if !goodFunc(v.Type()) {
56
                        panic(fmt.Errorf("can't handle multiple results from method/function %q", name))
57
                }
58
                out[name] = v
59
        }
60
}
61
 
62
// addFuncs adds to values the functions in funcs. It does no checking of the input -
63
// call addValueFuncs first.
64
func addFuncs(out, in FuncMap) {
65
        for name, fn := range in {
66
                out[name] = fn
67
        }
68
}
69
 
70
// goodFunc checks that the function or method has the right result signature.
71
func goodFunc(typ reflect.Type) bool {
72
        // We allow functions with 1 result or 2 results where the second is an error.
73
        switch {
74
        case typ.NumOut() == 1:
75
                return true
76
        case typ.NumOut() == 2 && typ.Out(1) == errorType:
77
                return true
78
        }
79
        return false
80
}
81
 
82
// findFunction looks for a function in the template, and global map.
83
func findFunction(name string, tmpl *Template) (reflect.Value, bool) {
84
        if tmpl != nil && tmpl.common != nil {
85
                if fn := tmpl.execFuncs[name]; fn.IsValid() {
86
                        return fn, true
87
                }
88
        }
89
        if fn := builtinFuncs[name]; fn.IsValid() {
90
                return fn, true
91
        }
92
        return reflect.Value{}, false
93
}
94
 
95
// Indexing.
96
 
97
// index returns the result of indexing its first argument by the following
98
// arguments.  Thus "index x 1 2 3" is, in Go syntax, x[1][2][3]. Each
99
// indexed item must be a map, slice, or array.
100
func index(item interface{}, indices ...interface{}) (interface{}, error) {
101
        v := reflect.ValueOf(item)
102
        for _, i := range indices {
103
                index := reflect.ValueOf(i)
104
                var isNil bool
105
                if v, isNil = indirect(v); isNil {
106
                        return nil, fmt.Errorf("index of nil pointer")
107
                }
108
                switch v.Kind() {
109
                case reflect.Array, reflect.Slice:
110
                        var x int64
111
                        switch index.Kind() {
112
                        case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
113
                                x = index.Int()
114
                        case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
115
                                x = int64(index.Uint())
116
                        default:
117
                                return nil, fmt.Errorf("cannot index slice/array with type %s", index.Type())
118
                        }
119
                        if x < 0 || x >= int64(v.Len()) {
120
                                return nil, fmt.Errorf("index out of range: %d", x)
121
                        }
122
                        v = v.Index(int(x))
123
                case reflect.Map:
124
                        if !index.Type().AssignableTo(v.Type().Key()) {
125
                                return nil, fmt.Errorf("%s is not index type for %s", index.Type(), v.Type())
126
                        }
127
                        if x := v.MapIndex(index); x.IsValid() {
128
                                v = x
129
                        } else {
130
                                v = reflect.Zero(v.Type().Key())
131
                        }
132
                default:
133
                        return nil, fmt.Errorf("can't index item of type %s", index.Type())
134
                }
135
        }
136
        return v.Interface(), nil
137
}
138
 
139
// Length
140
 
141
// length returns the length of the item, with an error if it has no defined length.
142
func length(item interface{}) (int, error) {
143
        v, isNil := indirect(reflect.ValueOf(item))
144
        if isNil {
145
                return 0, fmt.Errorf("len of nil pointer")
146
        }
147
        switch v.Kind() {
148
        case reflect.Array, reflect.Chan, reflect.Map, reflect.Slice, reflect.String:
149
                return v.Len(), nil
150
        }
151
        return 0, fmt.Errorf("len of type %s", v.Type())
152
}
153
 
154
// Boolean logic.
155
 
156
func truth(a interface{}) bool {
157
        t, _ := isTrue(reflect.ValueOf(a))
158
        return t
159
}
160
 
161
// and computes the Boolean AND of its arguments, returning
162
// the first false argument it encounters, or the last argument.
163
func and(arg0 interface{}, args ...interface{}) interface{} {
164
        if !truth(arg0) {
165
                return arg0
166
        }
167
        for i := range args {
168
                arg0 = args[i]
169
                if !truth(arg0) {
170
                        break
171
                }
172
        }
173
        return arg0
174
}
175
 
176
// or computes the Boolean OR of its arguments, returning
177
// the first true argument it encounters, or the last argument.
178
func or(arg0 interface{}, args ...interface{}) interface{} {
179
        if truth(arg0) {
180
                return arg0
181
        }
182
        for i := range args {
183
                arg0 = args[i]
184
                if truth(arg0) {
185
                        break
186
                }
187
        }
188
        return arg0
189
}
190
 
191
// not returns the Boolean negation of its argument.
192
func not(arg interface{}) (truth bool) {
193
        truth, _ = isTrue(reflect.ValueOf(arg))
194
        return !truth
195
}
196
 
197
// HTML escaping.
198
 
199
var (
200
        htmlQuot = []byte(""") // shorter than """
201
        htmlApos = []byte("'") // shorter than "'"
202
        htmlAmp  = []byte("&")
203
        htmlLt   = []byte("<")
204
        htmlGt   = []byte(">")
205
)
206
 
207
// HTMLEscape writes to w the escaped HTML equivalent of the plain text data b.
208
func HTMLEscape(w io.Writer, b []byte) {
209
        last := 0
210
        for i, c := range b {
211
                var html []byte
212
                switch c {
213
                case '"':
214
                        html = htmlQuot
215
                case '\'':
216
                        html = htmlApos
217
                case '&':
218
                        html = htmlAmp
219
                case '<':
220
                        html = htmlLt
221
                case '>':
222
                        html = htmlGt
223
                default:
224
                        continue
225
                }
226
                w.Write(b[last:i])
227
                w.Write(html)
228
                last = i + 1
229
        }
230
        w.Write(b[last:])
231
}
232
 
233
// HTMLEscapeString returns the escaped HTML equivalent of the plain text data s.
234
func HTMLEscapeString(s string) string {
235
        // Avoid allocation if we can.
236
        if strings.IndexAny(s, `'"&<>`) < 0 {
237
                return s
238
        }
239
        var b bytes.Buffer
240
        HTMLEscape(&b, []byte(s))
241
        return b.String()
242
}
243
 
244
// HTMLEscaper returns the escaped HTML equivalent of the textual
245
// representation of its arguments.
246
func HTMLEscaper(args ...interface{}) string {
247
        ok := false
248
        var s string
249
        if len(args) == 1 {
250
                s, ok = args[0].(string)
251
        }
252
        if !ok {
253
                s = fmt.Sprint(args...)
254
        }
255
        return HTMLEscapeString(s)
256
}
257
 
258
// JavaScript escaping.
259
 
260
var (
261
        jsLowUni = []byte(`\u00`)
262
        hex      = []byte("0123456789ABCDEF")
263
 
264
        jsBackslash = []byte(`\\`)
265
        jsApos      = []byte(`\'`)
266
        jsQuot      = []byte(`\"`)
267
        jsLt        = []byte(`\x3C`)
268
        jsGt        = []byte(`\x3E`)
269
)
270
 
271
// JSEscape writes to w the escaped JavaScript equivalent of the plain text data b.
272
func JSEscape(w io.Writer, b []byte) {
273
        last := 0
274
        for i := 0; i < len(b); i++ {
275
                c := b[i]
276
 
277
                if !jsIsSpecial(rune(c)) {
278
                        // fast path: nothing to do
279
                        continue
280
                }
281
                w.Write(b[last:i])
282
 
283
                if c < utf8.RuneSelf {
284
                        // Quotes, slashes and angle brackets get quoted.
285
                        // Control characters get written as \u00XX.
286
                        switch c {
287
                        case '\\':
288
                                w.Write(jsBackslash)
289
                        case '\'':
290
                                w.Write(jsApos)
291
                        case '"':
292
                                w.Write(jsQuot)
293
                        case '<':
294
                                w.Write(jsLt)
295
                        case '>':
296
                                w.Write(jsGt)
297
                        default:
298
                                w.Write(jsLowUni)
299
                                t, b := c>>4, c&0x0f
300
                                w.Write(hex[t : t+1])
301
                                w.Write(hex[b : b+1])
302
                        }
303
                } else {
304
                        // Unicode rune.
305
                        r, size := utf8.DecodeRune(b[i:])
306
                        if unicode.IsPrint(r) {
307
                                w.Write(b[i : i+size])
308
                        } else {
309
                                fmt.Fprintf(w, "\\u%04X", r)
310
                        }
311
                        i += size - 1
312
                }
313
                last = i + 1
314
        }
315
        w.Write(b[last:])
316
}
317
 
318
// JSEscapeString returns the escaped JavaScript equivalent of the plain text data s.
319
func JSEscapeString(s string) string {
320
        // Avoid allocation if we can.
321
        if strings.IndexFunc(s, jsIsSpecial) < 0 {
322
                return s
323
        }
324
        var b bytes.Buffer
325
        JSEscape(&b, []byte(s))
326
        return b.String()
327
}
328
 
329
func jsIsSpecial(r rune) bool {
330
        switch r {
331
        case '\\', '\'', '"', '<', '>':
332
                return true
333
        }
334
        return r < ' ' || utf8.RuneSelf <= r
335
}
336
 
337
// JSEscaper returns the escaped JavaScript equivalent of the textual
338
// representation of its arguments.
339
func JSEscaper(args ...interface{}) string {
340
        ok := false
341
        var s string
342
        if len(args) == 1 {
343
                s, ok = args[0].(string)
344
        }
345
        if !ok {
346
                s = fmt.Sprint(args...)
347
        }
348
        return JSEscapeString(s)
349
}
350
 
351
// URLQueryEscaper returns the escaped value of the textual representation of
352
// its arguments in a form suitable for embedding in a URL query.
353
func URLQueryEscaper(args ...interface{}) string {
354
        s, ok := "", false
355
        if len(args) == 1 {
356
                s, ok = args[0].(string)
357
        }
358
        if !ok {
359
                s = fmt.Sprint(args...)
360
        }
361
        return url.QueryEscape(s)
362
}

powered by: WebSVN 2.1.0

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