123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602 |
- // 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 https://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 its 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")
- }
- }
|