github.com/varialus/godfly@v0.0.0-20130904042352-1934f9f095ab/src/pkg/text/template/funcs.go (about) 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 "errors" 10 "fmt" 11 "io" 12 "net/url" 13 "reflect" 14 "strings" 15 "unicode" 16 "unicode/utf8" 17 ) 18 19 // FuncMap is the type of the map defining the mapping from names to functions. 20 // Each function must have either a single return value, or two return values of 21 // which the second has type error. In that case, if the second (error) 22 // return value evaluates to non-nil during execution, execution terminates and 23 // Execute returns that error. 24 type FuncMap map[string]interface{} 25 26 var builtins = FuncMap{ 27 "and": and, 28 "call": call, 29 "html": HTMLEscaper, 30 "index": index, 31 "js": JSEscaper, 32 "len": length, 33 "not": not, 34 "or": or, 35 "print": fmt.Sprint, 36 "printf": fmt.Sprintf, 37 "println": fmt.Sprintln, 38 "urlquery": URLQueryEscaper, 39 40 // Comparisons 41 "eq": eq, // == 42 "ge": ge, // >= 43 "gt": gt, // > 44 "le": le, // <= 45 "lt": lt, // < 46 "ne": ne, // != 47 } 48 49 var builtinFuncs = createValueFuncs(builtins) 50 51 // createValueFuncs turns a FuncMap into a map[string]reflect.Value 52 func createValueFuncs(funcMap FuncMap) map[string]reflect.Value { 53 m := make(map[string]reflect.Value) 54 addValueFuncs(m, funcMap) 55 return m 56 } 57 58 // addValueFuncs adds to values the functions in funcs, converting them to reflect.Values. 59 func addValueFuncs(out map[string]reflect.Value, in FuncMap) { 60 for name, fn := range in { 61 v := reflect.ValueOf(fn) 62 if v.Kind() != reflect.Func { 63 panic("value for " + name + " not a function") 64 } 65 if !goodFunc(v.Type()) { 66 panic(fmt.Errorf("can't install method/function %q with %d results", name, v.Type().NumOut())) 67 } 68 out[name] = v 69 } 70 } 71 72 // addFuncs adds to values the functions in funcs. It does no checking of the input - 73 // call addValueFuncs first. 74 func addFuncs(out, in FuncMap) { 75 for name, fn := range in { 76 out[name] = fn 77 } 78 } 79 80 // goodFunc checks that the function or method has the right result signature. 81 func goodFunc(typ reflect.Type) bool { 82 // We allow functions with 1 result or 2 results where the second is an error. 83 switch { 84 case typ.NumOut() == 1: 85 return true 86 case typ.NumOut() == 2 && typ.Out(1) == errorType: 87 return true 88 } 89 return false 90 } 91 92 // findFunction looks for a function in the template, and global map. 93 func findFunction(name string, tmpl *Template) (reflect.Value, bool) { 94 if tmpl != nil && tmpl.common != nil { 95 if fn := tmpl.execFuncs[name]; fn.IsValid() { 96 return fn, true 97 } 98 } 99 if fn := builtinFuncs[name]; fn.IsValid() { 100 return fn, true 101 } 102 return reflect.Value{}, false 103 } 104 105 // Indexing. 106 107 // index returns the result of indexing its first argument by the following 108 // arguments. Thus "index x 1 2 3" is, in Go syntax, x[1][2][3]. Each 109 // indexed item must be a map, slice, or array. 110 func index(item interface{}, indices ...interface{}) (interface{}, error) { 111 v := reflect.ValueOf(item) 112 for _, i := range indices { 113 index := reflect.ValueOf(i) 114 var isNil bool 115 if v, isNil = indirect(v); isNil { 116 return nil, fmt.Errorf("index of nil pointer") 117 } 118 switch v.Kind() { 119 case reflect.Array, reflect.Slice, reflect.String: 120 var x int64 121 switch index.Kind() { 122 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 123 x = index.Int() 124 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: 125 x = int64(index.Uint()) 126 default: 127 return nil, fmt.Errorf("cannot index slice/array with type %s", index.Type()) 128 } 129 if x < 0 || x >= int64(v.Len()) { 130 return nil, fmt.Errorf("index out of range: %d", x) 131 } 132 v = v.Index(int(x)) 133 case reflect.Map: 134 if !index.IsValid() { 135 index = reflect.Zero(v.Type().Key()) 136 } 137 if !index.Type().AssignableTo(v.Type().Key()) { 138 return nil, fmt.Errorf("%s is not index type for %s", index.Type(), v.Type()) 139 } 140 if x := v.MapIndex(index); x.IsValid() { 141 v = x 142 } else { 143 v = reflect.Zero(v.Type().Elem()) 144 } 145 default: 146 return nil, fmt.Errorf("can't index item of type %s", v.Type()) 147 } 148 } 149 return v.Interface(), nil 150 } 151 152 // Length 153 154 // length returns the length of the item, with an error if it has no defined length. 155 func length(item interface{}) (int, error) { 156 v, isNil := indirect(reflect.ValueOf(item)) 157 if isNil { 158 return 0, fmt.Errorf("len of nil pointer") 159 } 160 switch v.Kind() { 161 case reflect.Array, reflect.Chan, reflect.Map, reflect.Slice, reflect.String: 162 return v.Len(), nil 163 } 164 return 0, fmt.Errorf("len of type %s", v.Type()) 165 } 166 167 // Function invocation 168 169 // call returns the result of evaluating the first argument as a function. 170 // The function must return 1 result, or 2 results, the second of which is an error. 171 func call(fn interface{}, args ...interface{}) (interface{}, error) { 172 v := reflect.ValueOf(fn) 173 typ := v.Type() 174 if typ.Kind() != reflect.Func { 175 return nil, fmt.Errorf("non-function of type %s", typ) 176 } 177 if !goodFunc(typ) { 178 return nil, fmt.Errorf("function called with %d args; should be 1 or 2", typ.NumOut()) 179 } 180 numIn := typ.NumIn() 181 var dddType reflect.Type 182 if typ.IsVariadic() { 183 if len(args) < numIn-1 { 184 return nil, fmt.Errorf("wrong number of args: got %d want at least %d", len(args), numIn-1) 185 } 186 dddType = typ.In(numIn - 1).Elem() 187 } else { 188 if len(args) != numIn { 189 return nil, fmt.Errorf("wrong number of args: got %d want %d", len(args), numIn) 190 } 191 } 192 argv := make([]reflect.Value, len(args)) 193 for i, arg := range args { 194 value := reflect.ValueOf(arg) 195 // Compute the expected type. Clumsy because of variadics. 196 var argType reflect.Type 197 if !typ.IsVariadic() || i < numIn-1 { 198 argType = typ.In(i) 199 } else { 200 argType = dddType 201 } 202 if !value.IsValid() && canBeNil(argType) { 203 value = reflect.Zero(argType) 204 } 205 if !value.Type().AssignableTo(argType) { 206 return nil, fmt.Errorf("arg %d has type %s; should be %s", i, value.Type(), argType) 207 } 208 argv[i] = value 209 } 210 result := v.Call(argv) 211 if len(result) == 2 && !result[1].IsNil() { 212 return result[0].Interface(), result[1].Interface().(error) 213 } 214 return result[0].Interface(), nil 215 } 216 217 // Boolean logic. 218 219 func truth(a interface{}) bool { 220 t, _ := isTrue(reflect.ValueOf(a)) 221 return t 222 } 223 224 // and computes the Boolean AND of its arguments, returning 225 // the first false argument it encounters, or the last argument. 226 func and(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 // or computes the Boolean OR of its arguments, returning 240 // the first true argument it encounters, or the last argument. 241 func or(arg0 interface{}, args ...interface{}) interface{} { 242 if truth(arg0) { 243 return arg0 244 } 245 for i := range args { 246 arg0 = args[i] 247 if truth(arg0) { 248 break 249 } 250 } 251 return arg0 252 } 253 254 // not returns the Boolean negation of its argument. 255 func not(arg interface{}) (truth bool) { 256 truth, _ = isTrue(reflect.ValueOf(arg)) 257 return !truth 258 } 259 260 // Comparison. 261 262 // TODO: Perhaps allow comparison between signed and unsigned integers. 263 264 var ( 265 errBadComparisonType = errors.New("invalid type for comparison") 266 errBadComparison = errors.New("incompatible types for comparison") 267 errNoComparison = errors.New("missing argument for comparison") 268 ) 269 270 type kind int 271 272 const ( 273 invalidKind kind = iota 274 boolKind 275 complexKind 276 intKind 277 floatKind 278 integerKind 279 stringKind 280 uintKind 281 ) 282 283 func basicKind(v reflect.Value) (kind, error) { 284 switch v.Kind() { 285 case reflect.Bool: 286 return boolKind, nil 287 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 288 return intKind, nil 289 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: 290 return uintKind, nil 291 case reflect.Float32, reflect.Float64: 292 return floatKind, nil 293 case reflect.Complex64, reflect.Complex128: 294 return complexKind, nil 295 case reflect.String: 296 return stringKind, nil 297 } 298 return invalidKind, errBadComparisonType 299 } 300 301 // eq evaluates the comparison a == b || a == c || ... 302 func eq(arg1 interface{}, arg2 ...interface{}) (bool, error) { 303 v1 := reflect.ValueOf(arg1) 304 k1, err := basicKind(v1) 305 if err != nil { 306 return false, err 307 } 308 if len(arg2) == 0 { 309 return false, errNoComparison 310 } 311 for _, arg := range arg2 { 312 v2 := reflect.ValueOf(arg) 313 k2, err := basicKind(v2) 314 if err != nil { 315 return false, err 316 } 317 if k1 != k2 { 318 return false, errBadComparison 319 } 320 truth := false 321 switch k1 { 322 case boolKind: 323 truth = v1.Bool() == v2.Bool() 324 case complexKind: 325 truth = v1.Complex() == v2.Complex() 326 case floatKind: 327 truth = v1.Float() == v2.Float() 328 case intKind: 329 truth = v1.Int() == v2.Int() 330 case stringKind: 331 truth = v1.String() == v2.String() 332 case uintKind: 333 truth = v1.Uint() == v2.Uint() 334 default: 335 panic("invalid kind") 336 } 337 if truth { 338 return true, nil 339 } 340 } 341 return false, nil 342 } 343 344 // ne evaluates the comparison a != b. 345 func ne(arg1, arg2 interface{}) (bool, error) { 346 // != is the inverse of ==. 347 equal, err := eq(arg1, arg2) 348 return !equal, err 349 } 350 351 // lt evaluates the comparison a < b. 352 func lt(arg1, arg2 interface{}) (bool, error) { 353 v1 := reflect.ValueOf(arg1) 354 k1, err := basicKind(v1) 355 if err != nil { 356 return false, err 357 } 358 v2 := reflect.ValueOf(arg2) 359 k2, err := basicKind(v2) 360 if err != nil { 361 return false, err 362 } 363 if k1 != k2 { 364 return false, errBadComparison 365 } 366 truth := false 367 switch k1 { 368 case boolKind, complexKind: 369 return false, errBadComparisonType 370 case floatKind: 371 truth = v1.Float() < v2.Float() 372 case intKind: 373 truth = v1.Int() < v2.Int() 374 case stringKind: 375 truth = v1.String() < v2.String() 376 case uintKind: 377 truth = v1.Uint() < v2.Uint() 378 default: 379 panic("invalid kind") 380 } 381 return truth, nil 382 } 383 384 // le evaluates the comparison <= b. 385 func le(arg1, arg2 interface{}) (bool, error) { 386 // <= is < or ==. 387 lessThan, err := lt(arg1, arg2) 388 if lessThan || err != nil { 389 return lessThan, err 390 } 391 return eq(arg1, arg2) 392 } 393 394 // gt evaluates the comparison a > b. 395 func gt(arg1, arg2 interface{}) (bool, error) { 396 // > is the inverse of <=. 397 lessOrEqual, err := le(arg1, arg2) 398 if err != nil { 399 return false, err 400 } 401 return !lessOrEqual, nil 402 } 403 404 // ge evaluates the comparison a >= b. 405 func ge(arg1, arg2 interface{}) (bool, error) { 406 // >= is the inverse of <. 407 lessThan, err := lt(arg1, arg2) 408 if err != nil { 409 return false, err 410 } 411 return !lessThan, nil 412 } 413 414 // HTML escaping. 415 416 var ( 417 htmlQuot = []byte(""") // shorter than """ 418 htmlApos = []byte("'") // shorter than "'" and apos was not in HTML until HTML5 419 htmlAmp = []byte("&") 420 htmlLt = []byte("<") 421 htmlGt = []byte(">") 422 ) 423 424 // HTMLEscape writes to w the escaped HTML equivalent of the plain text data b. 425 func HTMLEscape(w io.Writer, b []byte) { 426 last := 0 427 for i, c := range b { 428 var html []byte 429 switch c { 430 case '"': 431 html = htmlQuot 432 case '\'': 433 html = htmlApos 434 case '&': 435 html = htmlAmp 436 case '<': 437 html = htmlLt 438 case '>': 439 html = htmlGt 440 default: 441 continue 442 } 443 w.Write(b[last:i]) 444 w.Write(html) 445 last = i + 1 446 } 447 w.Write(b[last:]) 448 } 449 450 // HTMLEscapeString returns the escaped HTML equivalent of the plain text data s. 451 func HTMLEscapeString(s string) string { 452 // Avoid allocation if we can. 453 if strings.IndexAny(s, `'"&<>`) < 0 { 454 return s 455 } 456 var b bytes.Buffer 457 HTMLEscape(&b, []byte(s)) 458 return b.String() 459 } 460 461 // HTMLEscaper returns the escaped HTML equivalent of the textual 462 // representation of its arguments. 463 func HTMLEscaper(args ...interface{}) string { 464 return HTMLEscapeString(evalArgs(args)) 465 } 466 467 // JavaScript escaping. 468 469 var ( 470 jsLowUni = []byte(`\u00`) 471 hex = []byte("0123456789ABCDEF") 472 473 jsBackslash = []byte(`\\`) 474 jsApos = []byte(`\'`) 475 jsQuot = []byte(`\"`) 476 jsLt = []byte(`\x3C`) 477 jsGt = []byte(`\x3E`) 478 ) 479 480 // JSEscape writes to w the escaped JavaScript equivalent of the plain text data b. 481 func JSEscape(w io.Writer, b []byte) { 482 last := 0 483 for i := 0; i < len(b); i++ { 484 c := b[i] 485 486 if !jsIsSpecial(rune(c)) { 487 // fast path: nothing to do 488 continue 489 } 490 w.Write(b[last:i]) 491 492 if c < utf8.RuneSelf { 493 // Quotes, slashes and angle brackets get quoted. 494 // Control characters get written as \u00XX. 495 switch c { 496 case '\\': 497 w.Write(jsBackslash) 498 case '\'': 499 w.Write(jsApos) 500 case '"': 501 w.Write(jsQuot) 502 case '<': 503 w.Write(jsLt) 504 case '>': 505 w.Write(jsGt) 506 default: 507 w.Write(jsLowUni) 508 t, b := c>>4, c&0x0f 509 w.Write(hex[t : t+1]) 510 w.Write(hex[b : b+1]) 511 } 512 } else { 513 // Unicode rune. 514 r, size := utf8.DecodeRune(b[i:]) 515 if unicode.IsPrint(r) { 516 w.Write(b[i : i+size]) 517 } else { 518 fmt.Fprintf(w, "\\u%04X", r) 519 } 520 i += size - 1 521 } 522 last = i + 1 523 } 524 w.Write(b[last:]) 525 } 526 527 // JSEscapeString returns the escaped JavaScript equivalent of the plain text data s. 528 func JSEscapeString(s string) string { 529 // Avoid allocation if we can. 530 if strings.IndexFunc(s, jsIsSpecial) < 0 { 531 return s 532 } 533 var b bytes.Buffer 534 JSEscape(&b, []byte(s)) 535 return b.String() 536 } 537 538 func jsIsSpecial(r rune) bool { 539 switch r { 540 case '\\', '\'', '"', '<', '>': 541 return true 542 } 543 return r < ' ' || utf8.RuneSelf <= r 544 } 545 546 // JSEscaper returns the escaped JavaScript equivalent of the textual 547 // representation of its arguments. 548 func JSEscaper(args ...interface{}) string { 549 return JSEscapeString(evalArgs(args)) 550 } 551 552 // URLQueryEscaper returns the escaped value of the textual representation of 553 // its arguments in a form suitable for embedding in a URL query. 554 func URLQueryEscaper(args ...interface{}) string { 555 return url.QueryEscape(evalArgs(args)) 556 } 557 558 // evalArgs formats the list of arguments into a string. It is therefore equivalent to 559 // fmt.Sprint(args...) 560 // except that each argument is indirected (if a pointer), as required, 561 // using the same rules as the default string evaluation during template 562 // execution. 563 func evalArgs(args []interface{}) string { 564 ok := false 565 var s string 566 // Fast path for simple common case. 567 if len(args) == 1 { 568 s, ok = args[0].(string) 569 } 570 if !ok { 571 for i, arg := range args { 572 a, ok := printableValue(reflect.ValueOf(arg)) 573 if ok { 574 args[i] = a 575 } // else left fmt do its thing 576 } 577 s = fmt.Sprint(args...) 578 } 579 return s 580 }