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  }