OSDN Git Service

Hulk did something
[bytom/vapor.git] / vendor / golang.org / x / text / unicode / cldr / resolve.go
diff --git a/vendor/golang.org/x/text/unicode/cldr/resolve.go b/vendor/golang.org/x/text/unicode/cldr/resolve.go
new file mode 100644 (file)
index 0000000..691b590
--- /dev/null
@@ -0,0 +1,602 @@
+// Copyright 2013 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 cldr
+
+// This file implements the various inheritance constructs defined by LDML.
+// See http://www.unicode.org/reports/tr35/#Inheritance_and_Validity
+// for more details.
+
+import (
+       "fmt"
+       "log"
+       "reflect"
+       "regexp"
+       "sort"
+       "strings"
+)
+
+// fieldIter iterates over fields in a struct. It includes
+// fields of embedded structs.
+type fieldIter struct {
+       v        reflect.Value
+       index, n []int
+}
+
+func iter(v reflect.Value) fieldIter {
+       if v.Kind() != reflect.Struct {
+               log.Panicf("value %v must be a struct", v)
+       }
+       i := fieldIter{
+               v:     v,
+               index: []int{0},
+               n:     []int{v.NumField()},
+       }
+       i.descent()
+       return i
+}
+
+func (i *fieldIter) descent() {
+       for f := i.field(); f.Anonymous && f.Type.NumField() > 0; f = i.field() {
+               i.index = append(i.index, 0)
+               i.n = append(i.n, f.Type.NumField())
+       }
+}
+
+func (i *fieldIter) done() bool {
+       return len(i.index) == 1 && i.index[0] >= i.n[0]
+}
+
+func skip(f reflect.StructField) bool {
+       return !f.Anonymous && (f.Name[0] < 'A' || f.Name[0] > 'Z')
+}
+
+func (i *fieldIter) next() {
+       for {
+               k := len(i.index) - 1
+               i.index[k]++
+               if i.index[k] < i.n[k] {
+                       if !skip(i.field()) {
+                               break
+                       }
+               } else {
+                       if k == 0 {
+                               return
+                       }
+                       i.index = i.index[:k]
+                       i.n = i.n[:k]
+               }
+       }
+       i.descent()
+}
+
+func (i *fieldIter) value() reflect.Value {
+       return i.v.FieldByIndex(i.index)
+}
+
+func (i *fieldIter) field() reflect.StructField {
+       return i.v.Type().FieldByIndex(i.index)
+}
+
+type visitor func(v reflect.Value) error
+
+var stopDescent = fmt.Errorf("do not recurse")
+
+func (f visitor) visit(x interface{}) error {
+       return f.visitRec(reflect.ValueOf(x))
+}
+
+// visit recursively calls f on all nodes in v.
+func (f visitor) visitRec(v reflect.Value) error {
+       if v.Kind() == reflect.Ptr {
+               if v.IsNil() {
+                       return nil
+               }
+               return f.visitRec(v.Elem())
+       }
+       if err := f(v); err != nil {
+               if err == stopDescent {
+                       return nil
+               }
+               return err
+       }
+       switch v.Kind() {
+       case reflect.Struct:
+               for i := iter(v); !i.done(); i.next() {
+                       if err := f.visitRec(i.value()); err != nil {
+                               return err
+                       }
+               }
+       case reflect.Slice:
+               for i := 0; i < v.Len(); i++ {
+                       if err := f.visitRec(v.Index(i)); err != nil {
+                               return err
+                       }
+               }
+       }
+       return nil
+}
+
+// getPath is used for error reporting purposes only.
+func getPath(e Elem) string {
+       if e == nil {
+               return "<nil>"
+       }
+       if e.enclosing() == nil {
+               return e.GetCommon().name
+       }
+       if e.GetCommon().Type == "" {
+               return fmt.Sprintf("%s.%s", getPath(e.enclosing()), e.GetCommon().name)
+       }
+       return fmt.Sprintf("%s.%s[type=%s]", getPath(e.enclosing()), e.GetCommon().name, e.GetCommon().Type)
+}
+
+// xmlName returns the xml name of the element or attribute
+func xmlName(f reflect.StructField) (name string, attr bool) {
+       tags := strings.Split(f.Tag.Get("xml"), ",")
+       for _, s := range tags {
+               attr = attr || s == "attr"
+       }
+       return tags[0], attr
+}
+
+func findField(v reflect.Value, key string) (reflect.Value, error) {
+       v = reflect.Indirect(v)
+       for i := iter(v); !i.done(); i.next() {
+               if n, _ := xmlName(i.field()); n == key {
+                       return i.value(), nil
+               }
+       }
+       return reflect.Value{}, fmt.Errorf("cldr: no field %q in element %#v", key, v.Interface())
+}
+
+var xpathPart = regexp.MustCompile(`(\pL+)(?:\[@(\pL+)='([\w-]+)'\])?`)
+
+func walkXPath(e Elem, path string) (res Elem, err error) {
+       for _, c := range strings.Split(path, "/") {
+               if c == ".." {
+                       if e = e.enclosing(); e == nil {
+                               panic("path ..")
+                               return nil, fmt.Errorf(`cldr: ".." moves past root in path %q`, path)
+                       }
+                       continue
+               } else if c == "" {
+                       continue
+               }
+               m := xpathPart.FindStringSubmatch(c)
+               if len(m) == 0 || len(m[0]) != len(c) {
+                       return nil, fmt.Errorf("cldr: syntax error in path component %q", c)
+               }
+               v, err := findField(reflect.ValueOf(e), m[1])
+               if err != nil {
+                       return nil, err
+               }
+               switch v.Kind() {
+               case reflect.Slice:
+                       i := 0
+                       if m[2] != "" || v.Len() > 1 {
+                               if m[2] == "" {
+                                       m[2] = "type"
+                                       if m[3] = e.GetCommon().Default(); m[3] == "" {
+                                               return nil, fmt.Errorf("cldr: type selector or default value needed for element %s", m[1])
+                                       }
+                               }
+                               for ; i < v.Len(); i++ {
+                                       vi := v.Index(i)
+                                       key, err := findField(vi.Elem(), m[2])
+                                       if err != nil {
+                                               return nil, err
+                                       }
+                                       key = reflect.Indirect(key)
+                                       if key.Kind() == reflect.String && key.String() == m[3] {
+                                               break
+                                       }
+                               }
+                       }
+                       if i == v.Len() || v.Index(i).IsNil() {
+                               return nil, fmt.Errorf("no %s found with %s==%s", m[1], m[2], m[3])
+                       }
+                       e = v.Index(i).Interface().(Elem)
+               case reflect.Ptr:
+                       if v.IsNil() {
+                               return nil, fmt.Errorf("cldr: element %q not found within element %q", m[1], e.GetCommon().name)
+                       }
+                       var ok bool
+                       if e, ok = v.Interface().(Elem); !ok {
+                               return nil, fmt.Errorf("cldr: %q is not an XML element", m[1])
+                       } else if m[2] != "" || m[3] != "" {
+                               return nil, fmt.Errorf("cldr: no type selector allowed for element %s", m[1])
+                       }
+               default:
+                       return nil, fmt.Errorf("cldr: %q is not an XML element", m[1])
+               }
+       }
+       return e, nil
+}
+
+const absPrefix = "//ldml/"
+
+func (cldr *CLDR) resolveAlias(e Elem, src, path string) (res Elem, err error) {
+       if src != "locale" {
+               if !strings.HasPrefix(path, absPrefix) {
+                       return nil, fmt.Errorf("cldr: expected absolute path, found %q", path)
+               }
+               path = path[len(absPrefix):]
+               if e, err = cldr.resolve(src); err != nil {
+                       return nil, err
+               }
+       }
+       return walkXPath(e, path)
+}
+
+func (cldr *CLDR) resolveAndMergeAlias(e Elem) error {
+       alias := e.GetCommon().Alias
+       if alias == nil {
+               return nil
+       }
+       a, err := cldr.resolveAlias(e, alias.Source, alias.Path)
+       if err != nil {
+               return fmt.Errorf("%v: error evaluating path %q: %v", getPath(e), alias.Path, err)
+       }
+       // Ensure alias node was already evaluated. TODO: avoid double evaluation.
+       err = cldr.resolveAndMergeAlias(a)
+       v := reflect.ValueOf(e).Elem()
+       for i := iter(reflect.ValueOf(a).Elem()); !i.done(); i.next() {
+               if vv := i.value(); vv.Kind() != reflect.Ptr || !vv.IsNil() {
+                       if _, attr := xmlName(i.field()); !attr {
+                               v.FieldByIndex(i.index).Set(vv)
+                       }
+               }
+       }
+       return err
+}
+
+func (cldr *CLDR) aliasResolver() visitor {
+       return func(v reflect.Value) (err error) {
+               if e, ok := v.Addr().Interface().(Elem); ok {
+                       err = cldr.resolveAndMergeAlias(e)
+                       if err == nil && blocking[e.GetCommon().name] {
+                               return stopDescent
+                       }
+               }
+               return err
+       }
+}
+
+// elements within blocking elements do not inherit.
+// Taken from CLDR's supplementalMetaData.xml.
+var blocking = map[string]bool{
+       "identity":         true,
+       "supplementalData": true,
+       "cldrTest":         true,
+       "collation":        true,
+       "transform":        true,
+}
+
+// Distinguishing attributes affect inheritance; two elements with different
+// distinguishing attributes are treated as different for purposes of inheritance,
+// except when such attributes occur in the indicated elements.
+// Taken from CLDR's supplementalMetaData.xml.
+var distinguishing = map[string][]string{
+       "key":        nil,
+       "request_id": nil,
+       "id":         nil,
+       "registry":   nil,
+       "alt":        nil,
+       "iso4217":    nil,
+       "iso3166":    nil,
+       "mzone":      nil,
+       "from":       nil,
+       "to":         nil,
+       "type": []string{
+               "abbreviationFallback",
+               "default",
+               "mapping",
+               "measurementSystem",
+               "preferenceOrdering",
+       },
+       "numberSystem": nil,
+}
+
+func in(set []string, s string) bool {
+       for _, v := range set {
+               if v == s {
+                       return true
+               }
+       }
+       return false
+}
+
+// attrKey computes a key based on the distinguishable attributes of
+// an element and it's values.
+func attrKey(v reflect.Value, exclude ...string) string {
+       parts := []string{}
+       ename := v.Interface().(Elem).GetCommon().name
+       v = v.Elem()
+       for i := iter(v); !i.done(); i.next() {
+               if name, attr := xmlName(i.field()); attr {
+                       if except, ok := distinguishing[name]; ok && !in(exclude, name) && !in(except, ename) {
+                               v := i.value()
+                               if v.Kind() == reflect.Ptr {
+                                       v = v.Elem()
+                               }
+                               if v.IsValid() {
+                                       parts = append(parts, fmt.Sprintf("%s=%s", name, v.String()))
+                               }
+                       }
+               }
+       }
+       sort.Strings(parts)
+       return strings.Join(parts, ";")
+}
+
+// Key returns a key for e derived from all distinguishing attributes
+// except those specified by exclude.
+func Key(e Elem, exclude ...string) string {
+       return attrKey(reflect.ValueOf(e), exclude...)
+}
+
+// linkEnclosing sets the enclosing element as well as the name
+// for all sub-elements of child, recursively.
+func linkEnclosing(parent, child Elem) {
+       child.setEnclosing(parent)
+       v := reflect.ValueOf(child).Elem()
+       for i := iter(v); !i.done(); i.next() {
+               vf := i.value()
+               if vf.Kind() == reflect.Slice {
+                       for j := 0; j < vf.Len(); j++ {
+                               linkEnclosing(child, vf.Index(j).Interface().(Elem))
+                       }
+               } else if vf.Kind() == reflect.Ptr && !vf.IsNil() && vf.Elem().Kind() == reflect.Struct {
+                       linkEnclosing(child, vf.Interface().(Elem))
+               }
+       }
+}
+
+func setNames(e Elem, name string) {
+       e.setName(name)
+       v := reflect.ValueOf(e).Elem()
+       for i := iter(v); !i.done(); i.next() {
+               vf := i.value()
+               name, _ = xmlName(i.field())
+               if vf.Kind() == reflect.Slice {
+                       for j := 0; j < vf.Len(); j++ {
+                               setNames(vf.Index(j).Interface().(Elem), name)
+                       }
+               } else if vf.Kind() == reflect.Ptr && !vf.IsNil() && vf.Elem().Kind() == reflect.Struct {
+                       setNames(vf.Interface().(Elem), name)
+               }
+       }
+}
+
+// deepCopy copies elements of v recursively.  All elements of v that may
+// be modified by inheritance are explicitly copied.
+func deepCopy(v reflect.Value) reflect.Value {
+       switch v.Kind() {
+       case reflect.Ptr:
+               if v.IsNil() || v.Elem().Kind() != reflect.Struct {
+                       return v
+               }
+               nv := reflect.New(v.Elem().Type())
+               nv.Elem().Set(v.Elem())
+               deepCopyRec(nv.Elem(), v.Elem())
+               return nv
+       case reflect.Slice:
+               nv := reflect.MakeSlice(v.Type(), v.Len(), v.Len())
+               for i := 0; i < v.Len(); i++ {
+                       deepCopyRec(nv.Index(i), v.Index(i))
+               }
+               return nv
+       }
+       panic("deepCopy: must be called with pointer or slice")
+}
+
+// deepCopyRec is only called by deepCopy.
+func deepCopyRec(nv, v reflect.Value) {
+       if v.Kind() == reflect.Struct {
+               t := v.Type()
+               for i := 0; i < v.NumField(); i++ {
+                       if name, attr := xmlName(t.Field(i)); name != "" && !attr {
+                               deepCopyRec(nv.Field(i), v.Field(i))
+                       }
+               }
+       } else {
+               nv.Set(deepCopy(v))
+       }
+}
+
+// newNode is used to insert a missing node during inheritance.
+func (cldr *CLDR) newNode(v, enc reflect.Value) reflect.Value {
+       n := reflect.New(v.Type())
+       for i := iter(v); !i.done(); i.next() {
+               if name, attr := xmlName(i.field()); name == "" || attr {
+                       n.Elem().FieldByIndex(i.index).Set(i.value())
+               }
+       }
+       n.Interface().(Elem).GetCommon().setEnclosing(enc.Addr().Interface().(Elem))
+       return n
+}
+
+// v, parent must be pointers to struct
+func (cldr *CLDR) inheritFields(v, parent reflect.Value) (res reflect.Value, err error) {
+       t := v.Type()
+       nv := reflect.New(t)
+       nv.Elem().Set(v)
+       for i := iter(v); !i.done(); i.next() {
+               vf := i.value()
+               f := i.field()
+               name, attr := xmlName(f)
+               if name == "" || attr {
+                       continue
+               }
+               pf := parent.FieldByIndex(i.index)
+               if blocking[name] {
+                       if vf.IsNil() {
+                               vf = pf
+                       }
+                       nv.Elem().FieldByIndex(i.index).Set(deepCopy(vf))
+                       continue
+               }
+               switch f.Type.Kind() {
+               case reflect.Ptr:
+                       if f.Type.Elem().Kind() == reflect.Struct {
+                               if !vf.IsNil() {
+                                       if vf, err = cldr.inheritStructPtr(vf, pf); err != nil {
+                                               return reflect.Value{}, err
+                                       }
+                                       vf.Interface().(Elem).setEnclosing(nv.Interface().(Elem))
+                                       nv.Elem().FieldByIndex(i.index).Set(vf)
+                               } else if !pf.IsNil() {
+                                       n := cldr.newNode(pf.Elem(), v)
+                                       if vf, err = cldr.inheritStructPtr(n, pf); err != nil {
+                                               return reflect.Value{}, err
+                                       }
+                                       vf.Interface().(Elem).setEnclosing(nv.Interface().(Elem))
+                                       nv.Elem().FieldByIndex(i.index).Set(vf)
+                               }
+                       }
+               case reflect.Slice:
+                       vf, err := cldr.inheritSlice(nv.Elem(), vf, pf)
+                       if err != nil {
+                               return reflect.Zero(t), err
+                       }
+                       nv.Elem().FieldByIndex(i.index).Set(vf)
+               }
+       }
+       return nv, nil
+}
+
+func root(e Elem) *LDML {
+       for ; e.enclosing() != nil; e = e.enclosing() {
+       }
+       return e.(*LDML)
+}
+
+// inheritStructPtr first merges possible aliases in with v and then inherits
+// any underspecified elements from parent.
+func (cldr *CLDR) inheritStructPtr(v, parent reflect.Value) (r reflect.Value, err error) {
+       if !v.IsNil() {
+               e := v.Interface().(Elem).GetCommon()
+               alias := e.Alias
+               if alias == nil && !parent.IsNil() {
+                       alias = parent.Interface().(Elem).GetCommon().Alias
+               }
+               if alias != nil {
+                       a, err := cldr.resolveAlias(v.Interface().(Elem), alias.Source, alias.Path)
+                       if a != nil {
+                               if v, err = cldr.inheritFields(v.Elem(), reflect.ValueOf(a).Elem()); err != nil {
+                                       return reflect.Value{}, err
+                               }
+                       }
+               }
+               if !parent.IsNil() {
+                       return cldr.inheritFields(v.Elem(), parent.Elem())
+               }
+       } else if parent.IsNil() {
+               panic("should not reach here")
+       }
+       return v, nil
+}
+
+// Must be slice of struct pointers.
+func (cldr *CLDR) inheritSlice(enc, v, parent reflect.Value) (res reflect.Value, err error) {
+       t := v.Type()
+       index := make(map[string]reflect.Value)
+       if !v.IsNil() {
+               for i := 0; i < v.Len(); i++ {
+                       vi := v.Index(i)
+                       key := attrKey(vi)
+                       index[key] = vi
+               }
+       }
+       if !parent.IsNil() {
+               for i := 0; i < parent.Len(); i++ {
+                       vi := parent.Index(i)
+                       key := attrKey(vi)
+                       if w, ok := index[key]; ok {
+                               index[key], err = cldr.inheritStructPtr(w, vi)
+                       } else {
+                               n := cldr.newNode(vi.Elem(), enc)
+                               index[key], err = cldr.inheritStructPtr(n, vi)
+                       }
+                       index[key].Interface().(Elem).setEnclosing(enc.Addr().Interface().(Elem))
+                       if err != nil {
+                               return v, err
+                       }
+               }
+       }
+       keys := make([]string, 0, len(index))
+       for k, _ := range index {
+               keys = append(keys, k)
+       }
+       sort.Strings(keys)
+       sl := reflect.MakeSlice(t, len(index), len(index))
+       for i, k := range keys {
+               sl.Index(i).Set(index[k])
+       }
+       return sl, nil
+}
+
+func parentLocale(loc string) string {
+       parts := strings.Split(loc, "_")
+       if len(parts) == 1 {
+               return "root"
+       }
+       parts = parts[:len(parts)-1]
+       key := strings.Join(parts, "_")
+       return key
+}
+
+func (cldr *CLDR) resolve(loc string) (res *LDML, err error) {
+       if r := cldr.resolved[loc]; r != nil {
+               return r, nil
+       }
+       x := cldr.RawLDML(loc)
+       if x == nil {
+               return nil, fmt.Errorf("cldr: unknown locale %q", loc)
+       }
+       var v reflect.Value
+       if loc == "root" {
+               x = deepCopy(reflect.ValueOf(x)).Interface().(*LDML)
+               linkEnclosing(nil, x)
+               err = cldr.aliasResolver().visit(x)
+       } else {
+               key := parentLocale(loc)
+               var parent *LDML
+               for ; cldr.locale[key] == nil; key = parentLocale(key) {
+               }
+               if parent, err = cldr.resolve(key); err != nil {
+                       return nil, err
+               }
+               v, err = cldr.inheritFields(reflect.ValueOf(x).Elem(), reflect.ValueOf(parent).Elem())
+               x = v.Interface().(*LDML)
+               linkEnclosing(nil, x)
+       }
+       if err != nil {
+               return nil, err
+       }
+       cldr.resolved[loc] = x
+       return x, err
+}
+
+// finalize finalizes the initialization of the raw LDML structs.  It also
+// removed unwanted fields, as specified by filter, so that they will not
+// be unnecessarily evaluated.
+func (cldr *CLDR) finalize(filter []string) {
+       for _, x := range cldr.locale {
+               if filter != nil {
+                       v := reflect.ValueOf(x).Elem()
+                       t := v.Type()
+                       for i := 0; i < v.NumField(); i++ {
+                               f := t.Field(i)
+                               name, _ := xmlName(f)
+                               if name != "" && name != "identity" && !in(filter, name) {
+                                       v.Field(i).Set(reflect.Zero(f.Type))
+                               }
+                       }
+               }
+               linkEnclosing(nil, x) // for resolving aliases and paths
+               setNames(x, "ldml")
+       }
+}