1
2
3
4
5 package cldrtree
6
7 import (
8 "bytes"
9 "fmt"
10 "io"
11 "reflect"
12 "strconv"
13 "strings"
14
15 "golang.org/x/text/internal/gen"
16 )
17
18 func generate(b *Builder, t *Tree, w *gen.CodeWriter) error {
19 fmt.Fprintln(w, `import "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
28 for _, e := range b.enums {
29
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
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
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
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
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
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 }
209
View as plain text