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// +build ignore
6
7package main
8
9import (
10	"flag"
11	"log"
12	"strconv"
13	"strings"
14
15	"golang.org/x/text/internal/cldrtree"
16	"golang.org/x/text/internal/gen"
17	"golang.org/x/text/language"
18	"golang.org/x/text/unicode/cldr"
19)
20
21var (
22	draft = flag.String("draft",
23		"contributed",
24		`Minimal draft requirements (approved, contributed, provisional, unconfirmed).`)
25)
26
27// TODO:
28// - Compile format patterns.
29// - Compress the large amount of redundancy in metazones.
30// - Split trees (with shared buckets) with data that is enough for default
31//   formatting of Go Time values and tables that are needed for larger
32//   variants.
33// - zone to metaZone mappings (in supplemental)
34// - Add more enum values and also some key maps for some of the elements.
35
36func main() {
37	gen.Init()
38
39	r := gen.OpenCLDRCoreZip()
40	defer r.Close()
41
42	d := &cldr.Decoder{}
43	d.SetDirFilter("supplemental", "main")
44	d.SetSectionFilter("dates")
45	data, err := d.DecodeZip(r)
46	if err != nil {
47		log.Fatalf("DecodeZip: %v", err)
48	}
49
50	dates := cldrtree.New("dates")
51	buildCLDRTree(data, dates)
52
53	w := gen.NewCodeWriter()
54	if err := dates.Gen(w); err != nil {
55		log.Fatal(err)
56	}
57	gen.WriteCLDRVersion(w)
58	w.WriteGoFile("tables.go", "date")
59
60	w = gen.NewCodeWriter()
61	if err := dates.GenTestData(w); err != nil {
62		log.Fatal(err)
63	}
64	w.WriteGoFile("data_test.go", "date")
65}
66
67func buildCLDRTree(data *cldr.CLDR, dates *cldrtree.Builder) {
68	context := cldrtree.Enum("context")
69	widthMap := func(s string) string {
70		// Align era with width values.
71		if r, ok := map[string]string{
72			"eraAbbr":   "abbreviated",
73			"eraNarrow": "narrow",
74			"eraNames":  "wide",
75		}[s]; ok {
76			s = r
77		}
78		// Prefix width to disambiguate with some overlapping length values.
79		return "width" + strings.Title(s)
80	}
81	width := cldrtree.EnumFunc("width", widthMap, "abbreviated", "narrow", "wide")
82	length := cldrtree.Enum("length", "short", "long")
83	month := cldrtree.Enum("month", "leap7")
84	relTime := cldrtree.EnumFunc("relTime", func(s string) string {
85		x, err := strconv.ParseInt(s, 10, 8)
86		if err != nil {
87			log.Fatal("Invalid number:", err)
88		}
89		return []string{
90			"before2",
91			"before1",
92			"current",
93			"after1",
94			"after2",
95			"after3",
96		}[x+2]
97	})
98	// Disambiguate keys like 'months' and 'sun'.
99	cycleType := cldrtree.EnumFunc("cycleType", func(s string) string {
100		return s + "CycleType"
101	})
102	field := cldrtree.EnumFunc("field", func(s string) string {
103		return s + "Field"
104	})
105	timeType := cldrtree.EnumFunc("timeType", func(s string) string {
106		if s == "" {
107			return "genericTime"
108		}
109		return s + "Time"
110	}, "generic")
111
112	zoneType := []cldrtree.Option{cldrtree.SharedType(), timeType}
113	metaZoneType := []cldrtree.Option{cldrtree.SharedType(), timeType}
114
115	for _, lang := range data.Locales() {
116		tag := language.Make(lang)
117		ldml := data.RawLDML(lang)
118		if ldml.Dates == nil {
119			continue
120		}
121		x := dates.Locale(tag)
122		if x := x.Index(ldml.Dates.Calendars); x != nil {
123			for _, cal := range ldml.Dates.Calendars.Calendar {
124				x := x.IndexFromType(cal)
125				if x := x.Index(cal.Months); x != nil {
126					for _, mc := range cal.Months.MonthContext {
127						x := x.IndexFromType(mc, context)
128						for _, mw := range mc.MonthWidth {
129							x := x.IndexFromType(mw, width)
130							for _, m := range mw.Month {
131								x.SetValue(m.Yeartype+m.Type, m, month)
132							}
133						}
134					}
135				}
136				if x := x.Index(cal.MonthPatterns); x != nil {
137					for _, mc := range cal.MonthPatterns.MonthPatternContext {
138						x := x.IndexFromType(mc, context)
139						for _, mw := range mc.MonthPatternWidth {
140							// Value is always leap, so no need to create a
141							// subindex.
142							for _, m := range mw.MonthPattern {
143								x.SetValue(mw.Type, m, width)
144							}
145						}
146					}
147				}
148				if x := x.Index(cal.CyclicNameSets); x != nil {
149					for _, cns := range cal.CyclicNameSets.CyclicNameSet {
150						x := x.IndexFromType(cns, cycleType)
151						for _, cc := range cns.CyclicNameContext {
152							x := x.IndexFromType(cc, context)
153							for _, cw := range cc.CyclicNameWidth {
154								x := x.IndexFromType(cw, width)
155								for _, c := range cw.CyclicName {
156									x.SetValue(c.Type, c)
157								}
158							}
159						}
160					}
161				}
162				if x := x.Index(cal.Days); x != nil {
163					for _, dc := range cal.Days.DayContext {
164						x := x.IndexFromType(dc, context)
165						for _, dw := range dc.DayWidth {
166							x := x.IndexFromType(dw, width)
167							for _, d := range dw.Day {
168								x.SetValue(d.Type, d)
169							}
170						}
171					}
172				}
173				if x := x.Index(cal.Quarters); x != nil {
174					for _, qc := range cal.Quarters.QuarterContext {
175						x := x.IndexFromType(qc, context)
176						for _, qw := range qc.QuarterWidth {
177							x := x.IndexFromType(qw, width)
178							for _, q := range qw.Quarter {
179								x.SetValue(q.Type, q)
180							}
181						}
182					}
183				}
184				if x := x.Index(cal.DayPeriods); x != nil {
185					for _, dc := range cal.DayPeriods.DayPeriodContext {
186						x := x.IndexFromType(dc, context)
187						for _, dw := range dc.DayPeriodWidth {
188							x := x.IndexFromType(dw, width)
189							for _, d := range dw.DayPeriod {
190								x.IndexFromType(d).SetValue(d.Alt, d)
191							}
192						}
193					}
194				}
195				if x := x.Index(cal.Eras); x != nil {
196					opts := []cldrtree.Option{width, cldrtree.SharedType()}
197					if x := x.Index(cal.Eras.EraNames, opts...); x != nil {
198						for _, e := range cal.Eras.EraNames.Era {
199							x.IndexFromAlt(e).SetValue(e.Type, e)
200						}
201					}
202					if x := x.Index(cal.Eras.EraAbbr, opts...); x != nil {
203						for _, e := range cal.Eras.EraAbbr.Era {
204							x.IndexFromAlt(e).SetValue(e.Type, e)
205						}
206					}
207					if x := x.Index(cal.Eras.EraNarrow, opts...); x != nil {
208						for _, e := range cal.Eras.EraNarrow.Era {
209							x.IndexFromAlt(e).SetValue(e.Type, e)
210						}
211					}
212				}
213				if x := x.Index(cal.DateFormats); x != nil {
214					for _, dfl := range cal.DateFormats.DateFormatLength {
215						x := x.IndexFromType(dfl, length)
216						for _, df := range dfl.DateFormat {
217							for _, p := range df.Pattern {
218								x.SetValue(p.Alt, p)
219							}
220						}
221					}
222				}
223				if x := x.Index(cal.TimeFormats); x != nil {
224					for _, tfl := range cal.TimeFormats.TimeFormatLength {
225						x := x.IndexFromType(tfl, length)
226						for _, tf := range tfl.TimeFormat {
227							for _, p := range tf.Pattern {
228								x.SetValue(p.Alt, p)
229							}
230						}
231					}
232				}
233				if x := x.Index(cal.DateTimeFormats); x != nil {
234					for _, dtfl := range cal.DateTimeFormats.DateTimeFormatLength {
235						x := x.IndexFromType(dtfl, length)
236						for _, dtf := range dtfl.DateTimeFormat {
237							for _, p := range dtf.Pattern {
238								x.SetValue(p.Alt, p)
239							}
240						}
241					}
242					// TODO:
243					// - appendItems
244					// - intervalFormats
245				}
246			}
247		}
248		// TODO: this is a lot of data and is probably relatively little used.
249		// Store this somewhere else.
250		if x := x.Index(ldml.Dates.Fields); x != nil {
251			for _, f := range ldml.Dates.Fields.Field {
252				x := x.IndexFromType(f, field)
253				for _, d := range f.DisplayName {
254					x.Index(d).SetValue(d.Alt, d)
255				}
256				for _, r := range f.Relative {
257					x.Index(r).SetValue(r.Type, r, relTime)
258				}
259				for _, rt := range f.RelativeTime {
260					x := x.Index(rt).IndexFromType(rt)
261					for _, p := range rt.RelativeTimePattern {
262						x.SetValue(p.Count, p)
263					}
264				}
265				for _, rp := range f.RelativePeriod {
266					x.Index(rp).SetValue(rp.Alt, rp)
267				}
268			}
269		}
270		if x := x.Index(ldml.Dates.TimeZoneNames); x != nil {
271			format := x.IndexWithName("zoneFormat")
272			for _, h := range ldml.Dates.TimeZoneNames.HourFormat {
273				format.SetValue(h.Element(), h)
274			}
275			for _, g := range ldml.Dates.TimeZoneNames.GmtFormat {
276				format.SetValue(g.Element(), g)
277			}
278			for _, g := range ldml.Dates.TimeZoneNames.GmtZeroFormat {
279				format.SetValue(g.Element(), g)
280			}
281			for _, r := range ldml.Dates.TimeZoneNames.RegionFormat {
282				x.Index(r).SetValue(r.Type, r, timeType)
283			}
284
285			set := func(x *cldrtree.Index, e []*cldr.Common, zone string) {
286				for _, n := range e {
287					x.Index(n, zoneType...).SetValue(zone, n)
288				}
289			}
290			zoneWidth := []cldrtree.Option{length, cldrtree.SharedType()}
291			zs := x.IndexWithName("zone")
292			for _, z := range ldml.Dates.TimeZoneNames.Zone {
293				for _, l := range z.Long {
294					x := zs.Index(l, zoneWidth...)
295					set(x, l.Generic, z.Type)
296					set(x, l.Standard, z.Type)
297					set(x, l.Daylight, z.Type)
298				}
299				for _, s := range z.Short {
300					x := zs.Index(s, zoneWidth...)
301					set(x, s.Generic, z.Type)
302					set(x, s.Standard, z.Type)
303					set(x, s.Daylight, z.Type)
304				}
305			}
306			set = func(x *cldrtree.Index, e []*cldr.Common, zone string) {
307				for _, n := range e {
308					x.Index(n, metaZoneType...).SetValue(zone, n)
309				}
310			}
311			zoneWidth = []cldrtree.Option{length, cldrtree.SharedType()}
312			zs = x.IndexWithName("metaZone")
313			for _, z := range ldml.Dates.TimeZoneNames.Metazone {
314				for _, l := range z.Long {
315					x := zs.Index(l, zoneWidth...)
316					set(x, l.Generic, z.Type)
317					set(x, l.Standard, z.Type)
318					set(x, l.Daylight, z.Type)
319				}
320				for _, s := range z.Short {
321					x := zs.Index(s, zoneWidth...)
322					set(x, s.Generic, z.Type)
323					set(x, s.Standard, z.Type)
324					set(x, s.Daylight, z.Type)
325				}
326			}
327		}
328	}
329}
330