OSDN Git Service

new repo
[bytom/vapor.git] / vendor / golang.org / x / text / feature / plural / message.go
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 plural
6
7 import (
8         "fmt"
9         "io/ioutil"
10         "reflect"
11         "strconv"
12
13         "golang.org/x/text/internal/catmsg"
14         "golang.org/x/text/internal/number"
15         "golang.org/x/text/language"
16         "golang.org/x/text/message/catalog"
17 )
18
19 // Interface is used for types that can determine their own plural form.
20 type Interface interface {
21         // PluralForm reports the plural form for the given language of the
22         // underlying value. It also returns the integer value. If the integer value
23         // is larger than fits in n, PluralForm may return a value modulo
24         // 10,000,000.
25         PluralForm(t language.Tag, scale int) (f Form, n int)
26 }
27
28 // Selectf returns the first case for which its selector is a match for the
29 // arg-th substitution argument to a formatting call, formatting it as indicated
30 // by format.
31 //
32 // The cases argument are pairs of selectors and messages. Selectors are of type
33 // string or Form. Messages are of type string or catalog.Message. A selector
34 // matches an argument if:
35 //    - it is "other" or Other
36 //    - it matches the plural form of the argument: "zero", "one", "two", "few",
37 //      or "many", or the equivalent Form
38 //    - it is of the form "=x" where x is an integer that matches the value of
39 //      the argument.
40 //    - it is of the form "<x" where x is an integer that is larger than the
41 //      argument.
42 //
43 // The format argument determines the formatting parameters for which to
44 // determine the plural form. This is especially relevant for non-integer
45 // values.
46 //
47 // The format string may be "", in which case a best-effort attempt is made to
48 // find a reasonable representation on which to base the plural form. Examples
49 // of format strings are:
50 //   - %.2f   decimal with scale 2
51 //   - %.2e   scientific notation with precision 3 (scale + 1)
52 //   - %d     integer
53 func Selectf(arg int, format string, cases ...interface{}) catalog.Message {
54         var p parser
55         // Intercept the formatting parameters of format by doing a dummy print.
56         fmt.Fprintf(ioutil.Discard, format, &p)
57         m := &message{arg, kindDefault, 0, cases}
58         switch p.verb {
59         case 'g':
60                 m.kind = kindPrecision
61                 m.scale = p.scale
62         case 'f':
63                 m.kind = kindScale
64                 m.scale = p.scale
65         case 'e':
66                 m.kind = kindScientific
67                 m.scale = p.scale
68         case 'd':
69                 m.kind = kindScale
70                 m.scale = 0
71         default:
72                 // TODO: do we need to handle errors?
73         }
74         return m
75 }
76
77 type parser struct {
78         verb  rune
79         scale int
80 }
81
82 func (p *parser) Format(s fmt.State, verb rune) {
83         p.verb = verb
84         p.scale = -1
85         if prec, ok := s.Precision(); ok {
86                 p.scale = prec
87         }
88 }
89
90 type message struct {
91         arg   int
92         kind  int
93         scale int
94         cases []interface{}
95 }
96
97 const (
98         // Start with non-ASCII to allow skipping values.
99         kindDefault    = 0x80 + iota
100         kindScale      // verb f, number of fraction digits follows
101         kindScientific // verb e, number of fraction digits follows
102         kindPrecision  // verb g, number of significant digits follows
103 )
104
105 var handle = catmsg.Register("golang.org/x/text/feature/plural:plural", execute)
106
107 func (m *message) Compile(e *catmsg.Encoder) error {
108         e.EncodeMessageType(handle)
109
110         e.EncodeUint(uint64(m.arg))
111
112         e.EncodeUint(uint64(m.kind))
113         if m.kind > kindDefault {
114                 e.EncodeUint(uint64(m.scale))
115         }
116
117         forms := validForms(cardinal, e.Language())
118
119         for i := 0; i < len(m.cases); {
120                 if err := compileSelector(e, forms, m.cases[i]); err != nil {
121                         return err
122                 }
123                 if i++; i >= len(m.cases) {
124                         return fmt.Errorf("plural: no message defined for selector %v", m.cases[i-1])
125                 }
126                 var msg catalog.Message
127                 switch x := m.cases[i].(type) {
128                 case string:
129                         msg = catalog.String(x)
130                 case catalog.Message:
131                         msg = x
132                 default:
133                         return fmt.Errorf("plural: message of type %T; must be string or catalog.Message", x)
134                 }
135                 if err := e.EncodeMessage(msg); err != nil {
136                         return err
137                 }
138                 i++
139         }
140         return nil
141 }
142
143 func compileSelector(e *catmsg.Encoder, valid []Form, selector interface{}) error {
144         form := Other
145         switch x := selector.(type) {
146         case string:
147                 if x == "" {
148                         return fmt.Errorf("plural: empty selector")
149                 }
150                 if c := x[0]; c == '=' || c == '<' {
151                         val, err := strconv.ParseUint(x[1:], 10, 16)
152                         if err != nil {
153                                 return fmt.Errorf("plural: invalid number in selector %q: %v", selector, err)
154                         }
155                         e.EncodeUint(uint64(c))
156                         e.EncodeUint(val)
157                         return nil
158                 }
159                 var ok bool
160                 form, ok = countMap[x]
161                 if !ok {
162                         return fmt.Errorf("plural: invalid plural form %q", selector)
163                 }
164         case Form:
165                 form = x
166         default:
167                 return fmt.Errorf("plural: selector of type %T; want string or Form", selector)
168         }
169
170         ok := false
171         for _, f := range valid {
172                 if f == form {
173                         ok = true
174                         break
175                 }
176         }
177         if !ok {
178                 return fmt.Errorf("plural: form %q not supported for language %q", selector, e.Language())
179         }
180         e.EncodeUint(uint64(form))
181         return nil
182 }
183
184 func execute(d *catmsg.Decoder) bool {
185         lang := d.Language()
186         argN := int(d.DecodeUint())
187         kind := int(d.DecodeUint())
188         scale := -1 // default
189         if kind > kindDefault {
190                 scale = int(d.DecodeUint())
191         }
192         form := Other
193         n := -1
194         if arg := d.Arg(argN); arg == nil {
195                 // Default to Other.
196         } else if x, ok := arg.(Interface); ok {
197                 // This covers lists and formatters from the number package.
198                 form, n = x.PluralForm(lang, scale)
199         } else {
200                 var f number.Formatter
201                 switch kind {
202                 case kindScale:
203                         f.InitDecimal(lang)
204                         f.SetScale(scale)
205                 case kindScientific:
206                         f.InitScientific(lang)
207                         f.SetScale(scale)
208                 case kindPrecision:
209                         f.InitDecimal(lang)
210                         f.SetPrecision(scale)
211                 case kindDefault:
212                         // sensible default
213                         f.InitDecimal(lang)
214                         if k := reflect.TypeOf(arg).Kind(); reflect.Int <= k && k <= reflect.Uintptr {
215                                 f.SetScale(0)
216                         } else {
217                                 f.SetScale(2)
218                         }
219                 }
220                 var dec number.Decimal // TODO: buffer in Printer
221                 dec.Convert(f.RoundingContext, arg)
222                 v := number.FormatDigits(&dec, f.RoundingContext)
223                 if !v.NaN && !v.Inf {
224                         form, n = cardinal.matchDisplayDigits(d.Language(), &v)
225                 }
226         }
227         for !d.Done() {
228                 f := d.DecodeUint()
229                 if (f == '=' && n == int(d.DecodeUint())) ||
230                         (f == '<' && 0 <= n && n < int(d.DecodeUint())) ||
231                         form == Form(f) ||
232                         Other == Form(f) {
233                         return d.ExecuteMessage()
234                 }
235                 d.SkipMessage()
236         }
237         return false
238 }