OSDN Git Service

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