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