type.go 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. // Copyright 2017 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. package cldrtree
  5. import (
  6. "log"
  7. "strconv"
  8. )
  9. // enumIndex is the numerical value of an enum value.
  10. type enumIndex int
  11. // An enum is a collection of enum values.
  12. type enum struct {
  13. name string // the Go type of the enum
  14. rename func(string) string
  15. keyMap map[string]enumIndex
  16. keys []string
  17. }
  18. // lookup returns the index for the enum corresponding to the string. If s
  19. // currently does not exist it will add the entry.
  20. func (e *enum) lookup(s string) enumIndex {
  21. if e.rename != nil {
  22. s = e.rename(s)
  23. }
  24. x, ok := e.keyMap[s]
  25. if !ok {
  26. if e.keyMap == nil {
  27. e.keyMap = map[string]enumIndex{}
  28. }
  29. u, err := strconv.ParseUint(s, 10, 32)
  30. if err == nil {
  31. for len(e.keys) <= int(u) {
  32. x := enumIndex(len(e.keys))
  33. s := strconv.Itoa(int(x))
  34. e.keyMap[s] = x
  35. e.keys = append(e.keys, s)
  36. }
  37. if e.keyMap[s] != enumIndex(u) {
  38. // TODO: handle more gracefully.
  39. log.Fatalf("cldrtree: mix of integer and non-integer for %q %v", s, e.keys)
  40. }
  41. return enumIndex(u)
  42. }
  43. x = enumIndex(len(e.keys))
  44. e.keyMap[s] = x
  45. e.keys = append(e.keys, s)
  46. }
  47. return x
  48. }
  49. // A typeInfo indicates the set of possible enum values and a mapping from
  50. // these values to subtypes.
  51. type typeInfo struct {
  52. enum *enum
  53. entries map[enumIndex]*typeInfo
  54. keyTypeInfo *typeInfo
  55. shareKeys bool
  56. }
  57. func (t *typeInfo) sharedKeys() bool {
  58. return t.shareKeys
  59. }
  60. func (t *typeInfo) lookupSubtype(s string, opts *options) (x enumIndex, sub *typeInfo) {
  61. if t.enum == nil {
  62. if t.enum = opts.sharedEnums; t.enum == nil {
  63. t.enum = &enum{}
  64. }
  65. }
  66. if opts.sharedEnums != nil && t.enum != opts.sharedEnums {
  67. panic("incompatible enums defined")
  68. }
  69. x = t.enum.lookup(s)
  70. if t.entries == nil {
  71. t.entries = map[enumIndex]*typeInfo{}
  72. }
  73. sub, ok := t.entries[x]
  74. if !ok {
  75. sub = opts.sharedType
  76. if sub == nil {
  77. sub = &typeInfo{}
  78. }
  79. t.entries[x] = sub
  80. }
  81. t.shareKeys = opts.sharedType != nil // For analysis purposes.
  82. return x, sub
  83. }
  84. // metaData includes information about subtypes, possibly sharing commonality
  85. // with sibling branches, and information about inheritance, which may differ
  86. // per branch.
  87. type metaData struct {
  88. b *Builder
  89. parent *metaData
  90. index enumIndex // index into the parent's subtype index
  91. key string
  92. elem string // XML element corresponding to this type.
  93. typeInfo *typeInfo
  94. lookup map[enumIndex]*metaData
  95. subs []*metaData
  96. inheritOffset int // always negative when applicable
  97. inheritIndex string // new value for field indicated by inheritOffset
  98. // inheritType *metaData
  99. }
  100. func (m *metaData) sub(key string, opts *options) *metaData {
  101. if m.lookup == nil {
  102. m.lookup = map[enumIndex]*metaData{}
  103. }
  104. enum, info := m.typeInfo.lookupSubtype(key, opts)
  105. sub := m.lookup[enum]
  106. if sub == nil {
  107. sub = &metaData{
  108. b: m.b,
  109. parent: m,
  110. index: enum,
  111. key: key,
  112. typeInfo: info,
  113. }
  114. m.lookup[enum] = sub
  115. m.subs = append(m.subs, sub)
  116. }
  117. return sub
  118. }
  119. func (m *metaData) validate() {
  120. for _, s := range m.subs {
  121. s.validate()
  122. }
  123. }