github.com/go-xe2/third@v1.0.3/golang.org/x/text/internal/cldrtree/generate.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 "bytes" 9 "fmt" 10 "io" 11 "reflect" 12 "strconv" 13 "strings" 14 15 "github.com/go-xe2/third/golang.org/x/text/internal/gen" 16 ) 17 18 func generate(b *Builder, t *Tree, w *gen.CodeWriter) error { 19 fmt.Fprintln(w, `import "github.com/go-xe2/third/golang.org/x/text/internal/cldrtree"`) 20 fmt.Fprintln(w) 21 22 fmt.Fprintf(w, "var tree = &cldrtree.Tree{locales, indices, buckets}\n\n") 23 24 w.WriteComment("Path values:\n" + b.stats()) 25 fmt.Fprintln(w) 26 27 // Generate enum types. 28 for _, e := range b.enums { 29 // Build enum types. 30 w.WriteComment("%s specifies a property of a CLDR field.", e.name) 31 fmt.Fprintf(w, "type %s uint16\n", e.name) 32 } 33 34 d, err := getEnumData(b) 35 if err != nil { 36 return err 37 } 38 fmt.Fprintln(w, "const (") 39 for i, k := range d.keys { 40 fmt.Fprintf(w, "%s %s = %d // %s\n", toCamel(k), d.enums[i], d.m[k], k) 41 } 42 fmt.Fprintln(w, ")") 43 44 w.WriteVar("locales", t.Locales) 45 w.WriteVar("indices", t.Indices) 46 47 // Generate string buckets. 48 fmt.Fprintln(w, "var buckets = []string{") 49 for i := range t.Buckets { 50 fmt.Fprintf(w, "bucket%d,\n", i) 51 } 52 fmt.Fprint(w, "}\n\n") 53 w.Size += int(reflect.TypeOf("").Size()) * len(t.Buckets) 54 55 // Generate string buckets. 56 for i, bucket := range t.Buckets { 57 w.WriteVar(fmt.Sprint("bucket", i), bucket) 58 } 59 return nil 60 } 61 62 func generateTestData(b *Builder, w *gen.CodeWriter) error { 63 d, err := getEnumData(b) 64 if err != nil { 65 return err 66 } 67 68 fmt.Fprintln(w) 69 fmt.Fprintln(w, "var enumMap = map[string]uint16{") 70 fmt.Fprintln(w, `"": 0,`) 71 for _, k := range d.keys { 72 fmt.Fprintf(w, "%q: %d,\n", k, d.m[k]) 73 } 74 fmt.Fprintln(w, "}") 75 return nil 76 } 77 78 func toCamel(s string) string { 79 p := strings.Split(s, "-") 80 for i, s := range p[1:] { 81 p[i+1] = strings.Title(s) 82 } 83 return strings.Replace(strings.Join(p, ""), "/", "", -1) 84 } 85 86 func (b *Builder) stats() string { 87 w := &bytes.Buffer{} 88 89 b.rootMeta.validate() 90 for _, es := range b.enums { 91 fmt.Fprintf(w, "<%s>\n", es.name) 92 printEnumValues(w, es, 1, nil) 93 } 94 fmt.Fprintln(w) 95 printEnums(w, b.rootMeta.typeInfo, 0) 96 fmt.Fprintln(w) 97 fmt.Fprintln(w, "Nr elem: ", len(b.strToBucket)) 98 fmt.Fprintln(w, "uniqued size: ", b.size) 99 fmt.Fprintln(w, "total string size: ", b.sizeAll) 100 fmt.Fprintln(w, "bucket waste: ", b.bucketWaste) 101 102 return w.String() 103 } 104 105 func printEnums(w io.Writer, s *typeInfo, indent int) { 106 idStr := strings.Repeat(" ", indent) + "- " 107 e := s.enum 108 if e == nil { 109 if len(s.entries) > 0 { 110 panic(fmt.Errorf("has entries but no enum values: %#v", s.entries)) 111 } 112 return 113 } 114 if e.name != "" { 115 fmt.Fprintf(w, "%s<%s>\n", idStr, e.name) 116 } else { 117 printEnumValues(w, e, indent, s) 118 } 119 if s.sharedKeys() { 120 for _, v := range s.entries { 121 printEnums(w, v, indent+1) 122 break 123 } 124 } 125 } 126 127 func printEnumValues(w io.Writer, e *enum, indent int, info *typeInfo) { 128 idStr := strings.Repeat(" ", indent) + "- " 129 for i := 0; i < len(e.keys); i++ { 130 fmt.Fprint(w, idStr) 131 k := e.keys[i] 132 if u, err := strconv.ParseUint(k, 10, 16); err == nil { 133 fmt.Fprintf(w, "%s", k) 134 // Skip contiguous integers 135 var v, last uint64 136 for i++; i < len(e.keys); i++ { 137 k = e.keys[i] 138 if v, err = strconv.ParseUint(k, 10, 16); err != nil { 139 break 140 } 141 last = v 142 } 143 if u < last { 144 fmt.Fprintf(w, `..%d`, last) 145 } 146 fmt.Fprintln(w) 147 if err != nil { 148 fmt.Fprintf(w, "%s%s\n", idStr, k) 149 } 150 } else if k == "" { 151 fmt.Fprintln(w, `""`) 152 } else { 153 fmt.Fprintf(w, "%s\n", k) 154 } 155 if info != nil && !info.sharedKeys() { 156 if e := info.entries[enumIndex(i)]; e != nil { 157 printEnums(w, e, indent+1) 158 } 159 } 160 } 161 } 162 163 func getEnumData(b *Builder) (*enumData, error) { 164 d := &enumData{m: map[string]int{}} 165 if errStr := d.insert(b.rootMeta.typeInfo); errStr != "" { 166 // TODO: consider returning the error. 167 return nil, fmt.Errorf("cldrtree: %s", errStr) 168 } 169 return d, nil 170 } 171 172 type enumData struct { 173 m map[string]int 174 keys []string 175 enums []string 176 } 177 178 func (d *enumData) insert(t *typeInfo) (errStr string) { 179 e := t.enum 180 if e == nil { 181 return "" 182 } 183 for i, k := range e.keys { 184 if _, err := strconv.ParseUint(k, 10, 16); err == nil { 185 // We don't include any enum that has integer values. 186 break 187 } 188 if v, ok := d.m[k]; ok { 189 if v != i { 190 return fmt.Sprintf("%q has value %d and %d", k, i, v) 191 } 192 } else { 193 d.m[k] = i 194 if k != "" { 195 d.keys = append(d.keys, k) 196 d.enums = append(d.enums, e.name) 197 } 198 } 199 } 200 for i := range t.enum.keys { 201 if e := t.entries[enumIndex(i)]; e != nil { 202 if errStr := d.insert(e); errStr != "" { 203 return fmt.Sprintf("%q>%v", t.enum.keys[i], errStr) 204 } 205 } 206 } 207 return "" 208 }