github.com/pankona/gometalinter@v2.0.11+incompatible/_linters/src/golang.org/x/text/unicode/cldr/resolve.go (about) 1 // Copyright 2013 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 cldr 6 7 // This file implements the various inheritance constructs defined by LDML. 8 // See http://www.unicode.org/reports/tr35/#Inheritance_and_Validity 9 // for more details. 10 11 import ( 12 "fmt" 13 "log" 14 "reflect" 15 "regexp" 16 "sort" 17 "strings" 18 ) 19 20 // fieldIter iterates over fields in a struct. It includes 21 // fields of embedded structs. 22 type fieldIter struct { 23 v reflect.Value 24 index, n []int 25 } 26 27 func iter(v reflect.Value) fieldIter { 28 if v.Kind() != reflect.Struct { 29 log.Panicf("value %v must be a struct", v) 30 } 31 i := fieldIter{ 32 v: v, 33 index: []int{0}, 34 n: []int{v.NumField()}, 35 } 36 i.descent() 37 return i 38 } 39 40 func (i *fieldIter) descent() { 41 for f := i.field(); f.Anonymous && f.Type.NumField() > 0; f = i.field() { 42 i.index = append(i.index, 0) 43 i.n = append(i.n, f.Type.NumField()) 44 } 45 } 46 47 func (i *fieldIter) done() bool { 48 return len(i.index) == 1 && i.index[0] >= i.n[0] 49 } 50 51 func skip(f reflect.StructField) bool { 52 return !f.Anonymous && (f.Name[0] < 'A' || f.Name[0] > 'Z') 53 } 54 55 func (i *fieldIter) next() { 56 for { 57 k := len(i.index) - 1 58 i.index[k]++ 59 if i.index[k] < i.n[k] { 60 if !skip(i.field()) { 61 break 62 } 63 } else { 64 if k == 0 { 65 return 66 } 67 i.index = i.index[:k] 68 i.n = i.n[:k] 69 } 70 } 71 i.descent() 72 } 73 74 func (i *fieldIter) value() reflect.Value { 75 return i.v.FieldByIndex(i.index) 76 } 77 78 func (i *fieldIter) field() reflect.StructField { 79 return i.v.Type().FieldByIndex(i.index) 80 } 81 82 type visitor func(v reflect.Value) error 83 84 var stopDescent = fmt.Errorf("do not recurse") 85 86 func (f visitor) visit(x interface{}) error { 87 return f.visitRec(reflect.ValueOf(x)) 88 } 89 90 // visit recursively calls f on all nodes in v. 91 func (f visitor) visitRec(v reflect.Value) error { 92 if v.Kind() == reflect.Ptr { 93 if v.IsNil() { 94 return nil 95 } 96 return f.visitRec(v.Elem()) 97 } 98 if err := f(v); err != nil { 99 if err == stopDescent { 100 return nil 101 } 102 return err 103 } 104 switch v.Kind() { 105 case reflect.Struct: 106 for i := iter(v); !i.done(); i.next() { 107 if err := f.visitRec(i.value()); err != nil { 108 return err 109 } 110 } 111 case reflect.Slice: 112 for i := 0; i < v.Len(); i++ { 113 if err := f.visitRec(v.Index(i)); err != nil { 114 return err 115 } 116 } 117 } 118 return nil 119 } 120 121 // getPath is used for error reporting purposes only. 122 func getPath(e Elem) string { 123 if e == nil { 124 return "<nil>" 125 } 126 if e.enclosing() == nil { 127 return e.GetCommon().name 128 } 129 if e.GetCommon().Type == "" { 130 return fmt.Sprintf("%s.%s", getPath(e.enclosing()), e.GetCommon().name) 131 } 132 return fmt.Sprintf("%s.%s[type=%s]", getPath(e.enclosing()), e.GetCommon().name, e.GetCommon().Type) 133 } 134 135 // xmlName returns the xml name of the element or attribute 136 func xmlName(f reflect.StructField) (name string, attr bool) { 137 tags := strings.Split(f.Tag.Get("xml"), ",") 138 for _, s := range tags { 139 attr = attr || s == "attr" 140 } 141 return tags[0], attr 142 } 143 144 func findField(v reflect.Value, key string) (reflect.Value, error) { 145 v = reflect.Indirect(v) 146 for i := iter(v); !i.done(); i.next() { 147 if n, _ := xmlName(i.field()); n == key { 148 return i.value(), nil 149 } 150 } 151 return reflect.Value{}, fmt.Errorf("cldr: no field %q in element %#v", key, v.Interface()) 152 } 153 154 var xpathPart = regexp.MustCompile(`(\pL+)(?:\[@(\pL+)='([\w-]+)'\])?`) 155 156 func walkXPath(e Elem, path string) (res Elem, err error) { 157 for _, c := range strings.Split(path, "/") { 158 if c == ".." { 159 if e = e.enclosing(); e == nil { 160 panic("path ..") 161 return nil, fmt.Errorf(`cldr: ".." moves past root in path %q`, path) 162 } 163 continue 164 } else if c == "" { 165 continue 166 } 167 m := xpathPart.FindStringSubmatch(c) 168 if len(m) == 0 || len(m[0]) != len(c) { 169 return nil, fmt.Errorf("cldr: syntax error in path component %q", c) 170 } 171 v, err := findField(reflect.ValueOf(e), m[1]) 172 if err != nil { 173 return nil, err 174 } 175 switch v.Kind() { 176 case reflect.Slice: 177 i := 0 178 if m[2] != "" || v.Len() > 1 { 179 if m[2] == "" { 180 m[2] = "type" 181 if m[3] = e.GetCommon().Default(); m[3] == "" { 182 return nil, fmt.Errorf("cldr: type selector or default value needed for element %s", m[1]) 183 } 184 } 185 for ; i < v.Len(); i++ { 186 vi := v.Index(i) 187 key, err := findField(vi.Elem(), m[2]) 188 if err != nil { 189 return nil, err 190 } 191 key = reflect.Indirect(key) 192 if key.Kind() == reflect.String && key.String() == m[3] { 193 break 194 } 195 } 196 } 197 if i == v.Len() || v.Index(i).IsNil() { 198 return nil, fmt.Errorf("no %s found with %s==%s", m[1], m[2], m[3]) 199 } 200 e = v.Index(i).Interface().(Elem) 201 case reflect.Ptr: 202 if v.IsNil() { 203 return nil, fmt.Errorf("cldr: element %q not found within element %q", m[1], e.GetCommon().name) 204 } 205 var ok bool 206 if e, ok = v.Interface().(Elem); !ok { 207 return nil, fmt.Errorf("cldr: %q is not an XML element", m[1]) 208 } else if m[2] != "" || m[3] != "" { 209 return nil, fmt.Errorf("cldr: no type selector allowed for element %s", m[1]) 210 } 211 default: 212 return nil, fmt.Errorf("cldr: %q is not an XML element", m[1]) 213 } 214 } 215 return e, nil 216 } 217 218 const absPrefix = "//ldml/" 219 220 func (cldr *CLDR) resolveAlias(e Elem, src, path string) (res Elem, err error) { 221 if src != "locale" { 222 if !strings.HasPrefix(path, absPrefix) { 223 return nil, fmt.Errorf("cldr: expected absolute path, found %q", path) 224 } 225 path = path[len(absPrefix):] 226 if e, err = cldr.resolve(src); err != nil { 227 return nil, err 228 } 229 } 230 return walkXPath(e, path) 231 } 232 233 func (cldr *CLDR) resolveAndMergeAlias(e Elem) error { 234 alias := e.GetCommon().Alias 235 if alias == nil { 236 return nil 237 } 238 a, err := cldr.resolveAlias(e, alias.Source, alias.Path) 239 if err != nil { 240 return fmt.Errorf("%v: error evaluating path %q: %v", getPath(e), alias.Path, err) 241 } 242 // Ensure alias node was already evaluated. TODO: avoid double evaluation. 243 err = cldr.resolveAndMergeAlias(a) 244 v := reflect.ValueOf(e).Elem() 245 for i := iter(reflect.ValueOf(a).Elem()); !i.done(); i.next() { 246 if vv := i.value(); vv.Kind() != reflect.Ptr || !vv.IsNil() { 247 if _, attr := xmlName(i.field()); !attr { 248 v.FieldByIndex(i.index).Set(vv) 249 } 250 } 251 } 252 return err 253 } 254 255 func (cldr *CLDR) aliasResolver() visitor { 256 return func(v reflect.Value) (err error) { 257 if e, ok := v.Addr().Interface().(Elem); ok { 258 err = cldr.resolveAndMergeAlias(e) 259 if err == nil && blocking[e.GetCommon().name] { 260 return stopDescent 261 } 262 } 263 return err 264 } 265 } 266 267 // elements within blocking elements do not inherit. 268 // Taken from CLDR's supplementalMetaData.xml. 269 var blocking = map[string]bool{ 270 "identity": true, 271 "supplementalData": true, 272 "cldrTest": true, 273 "collation": true, 274 "transform": true, 275 } 276 277 // Distinguishing attributes affect inheritance; two elements with different 278 // distinguishing attributes are treated as different for purposes of inheritance, 279 // except when such attributes occur in the indicated elements. 280 // Taken from CLDR's supplementalMetaData.xml. 281 var distinguishing = map[string][]string{ 282 "key": nil, 283 "request_id": nil, 284 "id": nil, 285 "registry": nil, 286 "alt": nil, 287 "iso4217": nil, 288 "iso3166": nil, 289 "mzone": nil, 290 "from": nil, 291 "to": nil, 292 "type": []string{ 293 "abbreviationFallback", 294 "default", 295 "mapping", 296 "measurementSystem", 297 "preferenceOrdering", 298 }, 299 "numberSystem": nil, 300 } 301 302 func in(set []string, s string) bool { 303 for _, v := range set { 304 if v == s { 305 return true 306 } 307 } 308 return false 309 } 310 311 // attrKey computes a key based on the distinguishable attributes of 312 // an element and it's values. 313 func attrKey(v reflect.Value, exclude ...string) string { 314 parts := []string{} 315 ename := v.Interface().(Elem).GetCommon().name 316 v = v.Elem() 317 for i := iter(v); !i.done(); i.next() { 318 if name, attr := xmlName(i.field()); attr { 319 if except, ok := distinguishing[name]; ok && !in(exclude, name) && !in(except, ename) { 320 v := i.value() 321 if v.Kind() == reflect.Ptr { 322 v = v.Elem() 323 } 324 if v.IsValid() { 325 parts = append(parts, fmt.Sprintf("%s=%s", name, v.String())) 326 } 327 } 328 } 329 } 330 sort.Strings(parts) 331 return strings.Join(parts, ";") 332 } 333 334 // Key returns a key for e derived from all distinguishing attributes 335 // except those specified by exclude. 336 func Key(e Elem, exclude ...string) string { 337 return attrKey(reflect.ValueOf(e), exclude...) 338 } 339 340 // linkEnclosing sets the enclosing element as well as the name 341 // for all sub-elements of child, recursively. 342 func linkEnclosing(parent, child Elem) { 343 child.setEnclosing(parent) 344 v := reflect.ValueOf(child).Elem() 345 for i := iter(v); !i.done(); i.next() { 346 vf := i.value() 347 if vf.Kind() == reflect.Slice { 348 for j := 0; j < vf.Len(); j++ { 349 linkEnclosing(child, vf.Index(j).Interface().(Elem)) 350 } 351 } else if vf.Kind() == reflect.Ptr && !vf.IsNil() && vf.Elem().Kind() == reflect.Struct { 352 linkEnclosing(child, vf.Interface().(Elem)) 353 } 354 } 355 } 356 357 func setNames(e Elem, name string) { 358 e.setName(name) 359 v := reflect.ValueOf(e).Elem() 360 for i := iter(v); !i.done(); i.next() { 361 vf := i.value() 362 name, _ = xmlName(i.field()) 363 if vf.Kind() == reflect.Slice { 364 for j := 0; j < vf.Len(); j++ { 365 setNames(vf.Index(j).Interface().(Elem), name) 366 } 367 } else if vf.Kind() == reflect.Ptr && !vf.IsNil() && vf.Elem().Kind() == reflect.Struct { 368 setNames(vf.Interface().(Elem), name) 369 } 370 } 371 } 372 373 // deepCopy copies elements of v recursively. All elements of v that may 374 // be modified by inheritance are explicitly copied. 375 func deepCopy(v reflect.Value) reflect.Value { 376 switch v.Kind() { 377 case reflect.Ptr: 378 if v.IsNil() || v.Elem().Kind() != reflect.Struct { 379 return v 380 } 381 nv := reflect.New(v.Elem().Type()) 382 nv.Elem().Set(v.Elem()) 383 deepCopyRec(nv.Elem(), v.Elem()) 384 return nv 385 case reflect.Slice: 386 nv := reflect.MakeSlice(v.Type(), v.Len(), v.Len()) 387 for i := 0; i < v.Len(); i++ { 388 deepCopyRec(nv.Index(i), v.Index(i)) 389 } 390 return nv 391 } 392 panic("deepCopy: must be called with pointer or slice") 393 } 394 395 // deepCopyRec is only called by deepCopy. 396 func deepCopyRec(nv, v reflect.Value) { 397 if v.Kind() == reflect.Struct { 398 t := v.Type() 399 for i := 0; i < v.NumField(); i++ { 400 if name, attr := xmlName(t.Field(i)); name != "" && !attr { 401 deepCopyRec(nv.Field(i), v.Field(i)) 402 } 403 } 404 } else { 405 nv.Set(deepCopy(v)) 406 } 407 } 408 409 // newNode is used to insert a missing node during inheritance. 410 func (cldr *CLDR) newNode(v, enc reflect.Value) reflect.Value { 411 n := reflect.New(v.Type()) 412 for i := iter(v); !i.done(); i.next() { 413 if name, attr := xmlName(i.field()); name == "" || attr { 414 n.Elem().FieldByIndex(i.index).Set(i.value()) 415 } 416 } 417 n.Interface().(Elem).GetCommon().setEnclosing(enc.Addr().Interface().(Elem)) 418 return n 419 } 420 421 // v, parent must be pointers to struct 422 func (cldr *CLDR) inheritFields(v, parent reflect.Value) (res reflect.Value, err error) { 423 t := v.Type() 424 nv := reflect.New(t) 425 nv.Elem().Set(v) 426 for i := iter(v); !i.done(); i.next() { 427 vf := i.value() 428 f := i.field() 429 name, attr := xmlName(f) 430 if name == "" || attr { 431 continue 432 } 433 pf := parent.FieldByIndex(i.index) 434 if blocking[name] { 435 if vf.IsNil() { 436 vf = pf 437 } 438 nv.Elem().FieldByIndex(i.index).Set(deepCopy(vf)) 439 continue 440 } 441 switch f.Type.Kind() { 442 case reflect.Ptr: 443 if f.Type.Elem().Kind() == reflect.Struct { 444 if !vf.IsNil() { 445 if vf, err = cldr.inheritStructPtr(vf, pf); err != nil { 446 return reflect.Value{}, err 447 } 448 vf.Interface().(Elem).setEnclosing(nv.Interface().(Elem)) 449 nv.Elem().FieldByIndex(i.index).Set(vf) 450 } else if !pf.IsNil() { 451 n := cldr.newNode(pf.Elem(), v) 452 if vf, err = cldr.inheritStructPtr(n, pf); err != nil { 453 return reflect.Value{}, err 454 } 455 vf.Interface().(Elem).setEnclosing(nv.Interface().(Elem)) 456 nv.Elem().FieldByIndex(i.index).Set(vf) 457 } 458 } 459 case reflect.Slice: 460 vf, err := cldr.inheritSlice(nv.Elem(), vf, pf) 461 if err != nil { 462 return reflect.Zero(t), err 463 } 464 nv.Elem().FieldByIndex(i.index).Set(vf) 465 } 466 } 467 return nv, nil 468 } 469 470 func root(e Elem) *LDML { 471 for ; e.enclosing() != nil; e = e.enclosing() { 472 } 473 return e.(*LDML) 474 } 475 476 // inheritStructPtr first merges possible aliases in with v and then inherits 477 // any underspecified elements from parent. 478 func (cldr *CLDR) inheritStructPtr(v, parent reflect.Value) (r reflect.Value, err error) { 479 if !v.IsNil() { 480 e := v.Interface().(Elem).GetCommon() 481 alias := e.Alias 482 if alias == nil && !parent.IsNil() { 483 alias = parent.Interface().(Elem).GetCommon().Alias 484 } 485 if alias != nil { 486 a, err := cldr.resolveAlias(v.Interface().(Elem), alias.Source, alias.Path) 487 if a != nil { 488 if v, err = cldr.inheritFields(v.Elem(), reflect.ValueOf(a).Elem()); err != nil { 489 return reflect.Value{}, err 490 } 491 } 492 } 493 if !parent.IsNil() { 494 return cldr.inheritFields(v.Elem(), parent.Elem()) 495 } 496 } else if parent.IsNil() { 497 panic("should not reach here") 498 } 499 return v, nil 500 } 501 502 // Must be slice of struct pointers. 503 func (cldr *CLDR) inheritSlice(enc, v, parent reflect.Value) (res reflect.Value, err error) { 504 t := v.Type() 505 index := make(map[string]reflect.Value) 506 if !v.IsNil() { 507 for i := 0; i < v.Len(); i++ { 508 vi := v.Index(i) 509 key := attrKey(vi) 510 index[key] = vi 511 } 512 } 513 if !parent.IsNil() { 514 for i := 0; i < parent.Len(); i++ { 515 vi := parent.Index(i) 516 key := attrKey(vi) 517 if w, ok := index[key]; ok { 518 index[key], err = cldr.inheritStructPtr(w, vi) 519 } else { 520 n := cldr.newNode(vi.Elem(), enc) 521 index[key], err = cldr.inheritStructPtr(n, vi) 522 } 523 index[key].Interface().(Elem).setEnclosing(enc.Addr().Interface().(Elem)) 524 if err != nil { 525 return v, err 526 } 527 } 528 } 529 keys := make([]string, 0, len(index)) 530 for k, _ := range index { 531 keys = append(keys, k) 532 } 533 sort.Strings(keys) 534 sl := reflect.MakeSlice(t, len(index), len(index)) 535 for i, k := range keys { 536 sl.Index(i).Set(index[k]) 537 } 538 return sl, nil 539 } 540 541 func parentLocale(loc string) string { 542 parts := strings.Split(loc, "_") 543 if len(parts) == 1 { 544 return "root" 545 } 546 parts = parts[:len(parts)-1] 547 key := strings.Join(parts, "_") 548 return key 549 } 550 551 func (cldr *CLDR) resolve(loc string) (res *LDML, err error) { 552 if r := cldr.resolved[loc]; r != nil { 553 return r, nil 554 } 555 x := cldr.RawLDML(loc) 556 if x == nil { 557 return nil, fmt.Errorf("cldr: unknown locale %q", loc) 558 } 559 var v reflect.Value 560 if loc == "root" { 561 x = deepCopy(reflect.ValueOf(x)).Interface().(*LDML) 562 linkEnclosing(nil, x) 563 err = cldr.aliasResolver().visit(x) 564 } else { 565 key := parentLocale(loc) 566 var parent *LDML 567 for ; cldr.locale[key] == nil; key = parentLocale(key) { 568 } 569 if parent, err = cldr.resolve(key); err != nil { 570 return nil, err 571 } 572 v, err = cldr.inheritFields(reflect.ValueOf(x).Elem(), reflect.ValueOf(parent).Elem()) 573 x = v.Interface().(*LDML) 574 linkEnclosing(nil, x) 575 } 576 if err != nil { 577 return nil, err 578 } 579 cldr.resolved[loc] = x 580 return x, err 581 } 582 583 // finalize finalizes the initialization of the raw LDML structs. It also 584 // removed unwanted fields, as specified by filter, so that they will not 585 // be unnecessarily evaluated. 586 func (cldr *CLDR) finalize(filter []string) { 587 for _, x := range cldr.locale { 588 if filter != nil { 589 v := reflect.ValueOf(x).Elem() 590 t := v.Type() 591 for i := 0; i < v.NumField(); i++ { 592 f := t.Field(i) 593 name, _ := xmlName(f) 594 if name != "" && name != "identity" && !in(filter, name) { 595 v.Field(i).Set(reflect.Zero(f.Type)) 596 } 597 } 598 } 599 linkEnclosing(nil, x) // for resolving aliases and paths 600 setNames(x, "ldml") 601 } 602 }