1 //This package is copied from Go library text/template.
2 //The original private functions eq, ge, gt, le, lt, and ne
3 //are exported as public functions.
25 // FuncMap is the type of the map defining the mapping from names to functions.
26 // Each function must have either a single return value, or two return values of
27 // which the second has type error. In that case, if the second (error)
28 // return value evaluates to non-nil during execution, execution terminates and
29 // Execute returns that error.
30 type FuncMap map[string]interface{}
32 var builtins = FuncMap{
42 "printf": fmt.Sprintf,
43 "println": fmt.Sprintln,
44 "urlquery": URLQueryEscaper,
55 var builtinFuncs = createValueFuncs(builtins)
57 // createValueFuncs turns a FuncMap into a map[string]reflect.Value
58 func createValueFuncs(funcMap FuncMap) map[string]reflect.Value {
59 m := make(map[string]reflect.Value)
60 addValueFuncs(m, funcMap)
64 // addValueFuncs adds to values the functions in funcs, converting them to reflect.Values.
65 func addValueFuncs(out map[string]reflect.Value, in FuncMap) {
66 for name, fn := range in {
67 v := reflect.ValueOf(fn)
68 if v.Kind() != reflect.Func {
69 panic("value for " + name + " not a function")
71 if !goodFunc(v.Type()) {
72 panic(fmt.Errorf("can't install method/function %q with %d results", name, v.Type().NumOut()))
78 // AddFuncs adds to values the functions in funcs. It does no checking of the input -
79 // call addValueFuncs first.
80 func addFuncs(out, in FuncMap) {
81 for name, fn := range in {
86 // goodFunc checks that the function or method has the right result signature.
87 func goodFunc(typ reflect.Type) bool {
88 // We allow functions with 1 result or 2 results where the second is an error.
90 case typ.NumOut() == 1:
92 case typ.NumOut() == 2 && typ.Out(1) == errorType:
98 // findFunction looks for a function in the template, and global map.
99 func findFunction(name string) (reflect.Value, bool) {
100 if fn := builtinFuncs[name]; fn.IsValid() {
103 return reflect.Value{}, false
108 // index returns the result of indexing its first argument by the following
109 // arguments. Thus "index x 1 2 3" is, in Go syntax, x[1][2][3]. Each
110 // indexed item must be a map, slice, or array.
111 func index(item interface{}, indices ...interface{}) (interface{}, error) {
112 v := reflect.ValueOf(item)
113 for _, i := range indices {
114 index := reflect.ValueOf(i)
116 if v, isNil = indirect(v); isNil {
117 return nil, fmt.Errorf("index of nil pointer")
120 case reflect.Array, reflect.Slice, reflect.String:
122 switch index.Kind() {
123 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
125 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
126 x = int64(index.Uint())
128 return nil, fmt.Errorf("cannot index slice/array with type %s", index.Type())
130 if x < 0 || x >= int64(v.Len()) {
131 return nil, fmt.Errorf("index out of range: %d", x)
135 if !index.IsValid() {
136 index = reflect.Zero(v.Type().Key())
138 if !index.Type().AssignableTo(v.Type().Key()) {
139 return nil, fmt.Errorf("%s is not index type for %s", index.Type(), v.Type())
141 if x := v.MapIndex(index); x.IsValid() {
144 v = reflect.Zero(v.Type().Elem())
147 return nil, fmt.Errorf("can't index item of type %s", v.Type())
150 return v.Interface(), nil
155 // length returns the length of the item, with an error if it has no defined length.
156 func length(item interface{}) (int, error) {
157 v, isNil := indirect(reflect.ValueOf(item))
159 return 0, fmt.Errorf("len of nil pointer")
162 case reflect.Array, reflect.Chan, reflect.Map, reflect.Slice, reflect.String:
165 return 0, fmt.Errorf("len of type %s", v.Type())
168 // Function invocation
170 // call returns the result of evaluating the first argument as a function.
171 // The function must return 1 result, or 2 results, the second of which is an error.
172 func call(fn interface{}, args ...interface{}) (interface{}, error) {
173 v := reflect.ValueOf(fn)
175 if typ.Kind() != reflect.Func {
176 return nil, fmt.Errorf("non-function of type %s", typ)
179 return nil, fmt.Errorf("function called with %d args; should be 1 or 2", typ.NumOut())
182 var dddType reflect.Type
183 if typ.IsVariadic() {
184 if len(args) < numIn-1 {
185 return nil, fmt.Errorf("wrong number of args: got %d want at least %d", len(args), numIn-1)
187 dddType = typ.In(numIn - 1).Elem()
189 if len(args) != numIn {
190 return nil, fmt.Errorf("wrong number of args: got %d want %d", len(args), numIn)
193 argv := make([]reflect.Value, len(args))
194 for i, arg := range args {
195 value := reflect.ValueOf(arg)
196 // Compute the expected type. Clumsy because of variadics.
197 var argType reflect.Type
198 if !typ.IsVariadic() || i < numIn-1 {
203 if !value.IsValid() && canBeNil(argType) {
204 value = reflect.Zero(argType)
206 if !value.Type().AssignableTo(argType) {
207 return nil, fmt.Errorf("arg %d has type %s; should be %s", i, value.Type(), argType)
211 result := v.Call(argv)
212 if len(result) == 2 && !result[1].IsNil() {
213 return result[0].Interface(), result[1].Interface().(error)
215 return result[0].Interface(), nil
220 func truth(a interface{}) bool {
221 t, _ := isTrue(reflect.ValueOf(a))
225 // and computes the Boolean AND of its arguments, returning
226 // the first false argument it encounters, or the last argument.
227 func and(arg0 interface{}, args ...interface{}) interface{} {
231 for i := range args {
240 // or computes the Boolean OR of its arguments, returning
241 // the first true argument it encounters, or the last argument.
242 func or(arg0 interface{}, args ...interface{}) interface{} {
246 for i := range args {
255 // not returns the Boolean negation of its argument.
256 func not(arg interface{}) (truth bool) {
257 truth, _ = isTrue(reflect.ValueOf(arg))
263 // TODO: Perhaps allow comparison between signed and unsigned integers.
266 errBadComparisonType = errors.New("invalid type for comparison")
267 errBadComparison = errors.New("incompatible types for comparison")
268 errNoComparison = errors.New("missing argument for comparison")
274 invalidKind kind = iota
284 func basicKind(v reflect.Value) (kind, error) {
288 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
290 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
292 case reflect.Float32, reflect.Float64:
293 return floatKind, nil
294 case reflect.Complex64, reflect.Complex128:
295 return complexKind, nil
297 return stringKind, nil
299 return invalidKind, errBadComparisonType
302 // eq evaluates the comparison a == b || a == c || ...
303 func eq(arg1 interface{}, arg2 ...interface{}) (bool, error) {
304 v1 := reflect.ValueOf(arg1)
305 k1, err := basicKind(v1)
310 return false, errNoComparison
312 for _, arg := range arg2 {
313 v2 := reflect.ValueOf(arg)
314 k2, err := basicKind(v2)
320 // Special case: Can compare integer values regardless of type's sign.
322 case k1 == intKind && k2 == uintKind:
323 truth = v1.Int() >= 0 && uint64(v1.Int()) == v2.Uint()
324 case k1 == uintKind && k2 == intKind:
325 truth = v2.Int() >= 0 && v1.Uint() == uint64(v2.Int())
327 return false, errBadComparison
332 truth = v1.Bool() == v2.Bool()
334 truth = v1.Complex() == v2.Complex()
336 truth = v1.Float() == v2.Float()
338 truth = v1.Int() == v2.Int()
340 truth = v1.String() == v2.String()
342 truth = v1.Uint() == v2.Uint()
344 panic("invalid kind")
354 // ne evaluates the comparison a != b.
355 func ne(arg1, arg2 interface{}) (bool, error) {
356 // != is the inverse of ==.
357 equal, err := eq(arg1, arg2)
361 // lt evaluates the comparison a < b.
362 func lt(arg1, arg2 interface{}) (bool, error) {
363 v1 := reflect.ValueOf(arg1)
364 k1, err := basicKind(v1)
368 v2 := reflect.ValueOf(arg2)
369 k2, err := basicKind(v2)
375 // Special case: Can compare integer values regardless of type's sign.
377 case k1 == intKind && k2 == uintKind:
378 truth = v1.Int() < 0 || uint64(v1.Int()) < v2.Uint()
379 case k1 == uintKind && k2 == intKind:
380 truth = v2.Int() >= 0 && v1.Uint() < uint64(v2.Int())
382 return false, errBadComparison
386 case boolKind, complexKind:
387 return false, errBadComparisonType
389 truth = v1.Float() < v2.Float()
391 truth = v1.Int() < v2.Int()
393 truth = v1.String() < v2.String()
395 truth = v1.Uint() < v2.Uint()
397 panic("invalid kind")
403 // le evaluates the comparison <= b.
404 func le(arg1, arg2 interface{}) (bool, error) {
406 lessThan, err := lt(arg1, arg2)
407 if lessThan || err != nil {
410 return eq(arg1, arg2)
413 // gt evaluates the comparison a > b.
414 func gt(arg1, arg2 interface{}) (bool, error) {
415 // > is the inverse of <=.
416 lessOrEqual, err := le(arg1, arg2)
420 return !lessOrEqual, nil
423 // ge evaluates the comparison a >= b.
424 func ge(arg1, arg2 interface{}) (bool, error) {
425 // >= is the inverse of <.
426 lessThan, err := lt(arg1, arg2)
430 return !lessThan, nil
436 htmlQuot = []byte(""") // shorter than """
437 htmlApos = []byte("'") // shorter than "'" and apos was not in HTML until HTML5
438 htmlAmp = []byte("&")
439 htmlLt = []byte("<")
440 htmlGt = []byte(">")
443 // HTMLEscape writes to w the escaped HTML equivalent of the plain text data b.
444 func HTMLEscape(w io.Writer, b []byte) {
446 for i, c := range b {
469 // HTMLEscapeString returns the escaped HTML equivalent of the plain text data s.
470 func HTMLEscapeString(s string) string {
471 // Avoid allocation if we can.
472 if strings.IndexAny(s, `'"&<>`) < 0 {
476 HTMLEscape(&b, []byte(s))
480 // HTMLEscaper returns the escaped HTML equivalent of the textual
481 // representation of its arguments.
482 func HTMLEscaper(args ...interface{}) string {
483 return HTMLEscapeString(evalArgs(args))
486 // JavaScript escaping.
489 jsLowUni = []byte(`\u00`)
490 hex = []byte("0123456789ABCDEF")
492 jsBackslash = []byte(`\\`)
493 jsApos = []byte(`\'`)
494 jsQuot = []byte(`\"`)
495 jsLt = []byte(`\x3C`)
496 jsGt = []byte(`\x3E`)
499 // JSEscape writes to w the escaped JavaScript equivalent of the plain text data b.
500 func JSEscape(w io.Writer, b []byte) {
502 for i := 0; i < len(b); i++ {
505 if !jsIsSpecial(rune(c)) {
506 // fast path: nothing to do
511 if c < utf8.RuneSelf {
512 // Quotes, slashes and angle brackets get quoted.
513 // Control characters get written as \u00XX.
528 w.Write(hex[t : t+1])
529 w.Write(hex[b : b+1])
533 r, size := utf8.DecodeRune(b[i:])
534 if unicode.IsPrint(r) {
535 w.Write(b[i : i+size])
537 fmt.Fprintf(w, "\\u%04X", r)
546 // JSEscapeString returns the escaped JavaScript equivalent of the plain text data s.
547 func JSEscapeString(s string) string {
548 // Avoid allocation if we can.
549 if strings.IndexFunc(s, jsIsSpecial) < 0 {
553 JSEscape(&b, []byte(s))
557 func jsIsSpecial(r rune) bool {
559 case '\\', '\'', '"', '<', '>':
562 return r < ' ' || utf8.RuneSelf <= r
565 // JSEscaper returns the escaped JavaScript equivalent of the textual
566 // representation of its arguments.
567 func JSEscaper(args ...interface{}) string {
568 return JSEscapeString(evalArgs(args))
571 // URLQueryEscaper returns the escaped value of the textual representation of
572 // its arguments in a form suitable for embedding in a URL query.
573 func URLQueryEscaper(args ...interface{}) string {
574 return url.QueryEscape(evalArgs(args))
577 // evalArgs formats the list of arguments into a string. It is therefore equivalent to
578 // fmt.Sprint(args...)
579 // except that each argument is indirected (if a pointer), as required,
580 // using the same rules as the default string evaluation during template
582 func evalArgs(args []interface{}) string {
585 // Fast path for simple common case.
587 s, ok = args[0].(string)
590 for i, arg := range args {
591 a, ok := printableValue(reflect.ValueOf(arg))
594 } // else left fmt do its thing
596 s = fmt.Sprint(args...)