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