URL
https://opencores.org/ocsvn/openrisc/openrisc/trunk
Subversion Repositories openrisc
[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [libgo/] [go/] [text/] [template/] [funcs.go] - Rev 747
Compare with Previous | Blame | View Log
// Copyright 2011 The Go Authors. All rights reserved.// Use of this source code is governed by a BSD-style// license that can be found in the LICENSE file.package templateimport ("bytes""fmt""io""net/url""reflect""strings""unicode""unicode/utf8")// FuncMap is the type of the map defining the mapping from names to functions.// Each function must have either a single return value, or two return values of// which the second has type error. In that case, if the second (error)// argument evaluates to non-nil during execution, execution terminates and// Execute returns that error.type FuncMap map[string]interface{}var builtins = FuncMap{"and": and,"html": HTMLEscaper,"index": index,"js": JSEscaper,"len": length,"not": not,"or": or,"print": fmt.Sprint,"printf": fmt.Sprintf,"println": fmt.Sprintln,"urlquery": URLQueryEscaper,}var builtinFuncs = createValueFuncs(builtins)// createValueFuncs turns a FuncMap into a map[string]reflect.Valuefunc createValueFuncs(funcMap FuncMap) map[string]reflect.Value {m := make(map[string]reflect.Value)addValueFuncs(m, funcMap)return m}// addValueFuncs adds to values the functions in funcs, converting them to reflect.Values.func addValueFuncs(out map[string]reflect.Value, in FuncMap) {for name, fn := range in {v := reflect.ValueOf(fn)if v.Kind() != reflect.Func {panic("value for " + name + " not a function")}if !goodFunc(v.Type()) {panic(fmt.Errorf("can't handle multiple results from method/function %q", name))}out[name] = v}}// addFuncs adds to values the functions in funcs. It does no checking of the input -// call addValueFuncs first.func addFuncs(out, in FuncMap) {for name, fn := range in {out[name] = fn}}// goodFunc checks that the function or method has the right result signature.func goodFunc(typ reflect.Type) bool {// We allow functions with 1 result or 2 results where the second is an error.switch {case typ.NumOut() == 1:return truecase typ.NumOut() == 2 && typ.Out(1) == errorType:return true}return false}// findFunction looks for a function in the template, and global map.func findFunction(name string, tmpl *Template) (reflect.Value, bool) {if tmpl != nil && tmpl.common != nil {if fn := tmpl.execFuncs[name]; fn.IsValid() {return fn, true}}if fn := builtinFuncs[name]; fn.IsValid() {return fn, true}return reflect.Value{}, false}// Indexing.// index returns the result of indexing its first argument by the following// arguments. Thus "index x 1 2 3" is, in Go syntax, x[1][2][3]. Each// indexed item must be a map, slice, or array.func index(item interface{}, indices ...interface{}) (interface{}, error) {v := reflect.ValueOf(item)for _, i := range indices {index := reflect.ValueOf(i)var isNil boolif v, isNil = indirect(v); isNil {return nil, fmt.Errorf("index of nil pointer")}switch v.Kind() {case reflect.Array, reflect.Slice:var x int64switch index.Kind() {case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:x = index.Int()case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:x = int64(index.Uint())default:return nil, fmt.Errorf("cannot index slice/array with type %s", index.Type())}if x < 0 || x >= int64(v.Len()) {return nil, fmt.Errorf("index out of range: %d", x)}v = v.Index(int(x))case reflect.Map:if !index.Type().AssignableTo(v.Type().Key()) {return nil, fmt.Errorf("%s is not index type for %s", index.Type(), v.Type())}if x := v.MapIndex(index); x.IsValid() {v = x} else {v = reflect.Zero(v.Type().Key())}default:return nil, fmt.Errorf("can't index item of type %s", index.Type())}}return v.Interface(), nil}// Length// length returns the length of the item, with an error if it has no defined length.func length(item interface{}) (int, error) {v, isNil := indirect(reflect.ValueOf(item))if isNil {return 0, fmt.Errorf("len of nil pointer")}switch v.Kind() {case reflect.Array, reflect.Chan, reflect.Map, reflect.Slice, reflect.String:return v.Len(), nil}return 0, fmt.Errorf("len of type %s", v.Type())}// Boolean logic.func truth(a interface{}) bool {t, _ := isTrue(reflect.ValueOf(a))return t}// and computes the Boolean AND of its arguments, returning// the first false argument it encounters, or the last argument.func and(arg0 interface{}, args ...interface{}) interface{} {if !truth(arg0) {return arg0}for i := range args {arg0 = args[i]if !truth(arg0) {break}}return arg0}// or computes the Boolean OR of its arguments, returning// the first true argument it encounters, or the last argument.func or(arg0 interface{}, args ...interface{}) interface{} {if truth(arg0) {return arg0}for i := range args {arg0 = args[i]if truth(arg0) {break}}return arg0}// not returns the Boolean negation of its argument.func not(arg interface{}) (truth bool) {truth, _ = isTrue(reflect.ValueOf(arg))return !truth}// HTML escaping.var (htmlQuot = []byte(""") // shorter than """htmlApos = []byte("'") // shorter than "'"htmlAmp = []byte("&")htmlLt = []byte("<")htmlGt = []byte(">"))// HTMLEscape writes to w the escaped HTML equivalent of the plain text data b.func HTMLEscape(w io.Writer, b []byte) {last := 0for i, c := range b {var html []byteswitch c {case '"':html = htmlQuotcase '\'':html = htmlAposcase '&':html = htmlAmpcase '<':html = htmlLtcase '>':html = htmlGtdefault:continue}w.Write(b[last:i])w.Write(html)last = i + 1}w.Write(b[last:])}// HTMLEscapeString returns the escaped HTML equivalent of the plain text data s.func HTMLEscapeString(s string) string {// Avoid allocation if we can.if strings.IndexAny(s, `'"&<>`) < 0 {return s}var b bytes.BufferHTMLEscape(&b, []byte(s))return b.String()}// HTMLEscaper returns the escaped HTML equivalent of the textual// representation of its arguments.func HTMLEscaper(args ...interface{}) string {ok := falsevar s stringif len(args) == 1 {s, ok = args[0].(string)}if !ok {s = fmt.Sprint(args...)}return HTMLEscapeString(s)}// JavaScript escaping.var (jsLowUni = []byte(`\u00`)hex = []byte("0123456789ABCDEF")jsBackslash = []byte(`\\`)jsApos = []byte(`\'`)jsQuot = []byte(`\"`)jsLt = []byte(`\x3C`)jsGt = []byte(`\x3E`))// JSEscape writes to w the escaped JavaScript equivalent of the plain text data b.func JSEscape(w io.Writer, b []byte) {last := 0for i := 0; i < len(b); i++ {c := b[i]if !jsIsSpecial(rune(c)) {// fast path: nothing to docontinue}w.Write(b[last:i])if c < utf8.RuneSelf {// Quotes, slashes and angle brackets get quoted.// Control characters get written as \u00XX.switch c {case '\\':w.Write(jsBackslash)case '\'':w.Write(jsApos)case '"':w.Write(jsQuot)case '<':w.Write(jsLt)case '>':w.Write(jsGt)default:w.Write(jsLowUni)t, b := c>>4, c&0x0fw.Write(hex[t : t+1])w.Write(hex[b : b+1])}} else {// Unicode rune.r, size := utf8.DecodeRune(b[i:])if unicode.IsPrint(r) {w.Write(b[i : i+size])} else {fmt.Fprintf(w, "\\u%04X", r)}i += size - 1}last = i + 1}w.Write(b[last:])}// JSEscapeString returns the escaped JavaScript equivalent of the plain text data s.func JSEscapeString(s string) string {// Avoid allocation if we can.if strings.IndexFunc(s, jsIsSpecial) < 0 {return s}var b bytes.BufferJSEscape(&b, []byte(s))return b.String()}func jsIsSpecial(r rune) bool {switch r {case '\\', '\'', '"', '<', '>':return true}return r < ' ' || utf8.RuneSelf <= r}// JSEscaper returns the escaped JavaScript equivalent of the textual// representation of its arguments.func JSEscaper(args ...interface{}) string {ok := falsevar s stringif len(args) == 1 {s, ok = args[0].(string)}if !ok {s = fmt.Sprint(args...)}return JSEscapeString(s)}// URLQueryEscaper returns the escaped value of the textual representation of// its arguments in a form suitable for embedding in a URL query.func URLQueryEscaper(args ...interface{}) string {s, ok := "", falseif len(args) == 1 {s, ok = args[0].(string)}if !ok {s = fmt.Sprint(args...)}return url.QueryEscape(s)}
