1
2
3
4
5 package number
6
7 import (
8 "errors"
9 "unicode/utf8"
10 )
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41 type Pattern struct {
42 RoundingContext
43
44 Affix string
45 Offset uint16
46 NegOffset uint16
47 PadRune rune
48 FormatWidth uint16
49
50 GroupingSize [2]uint8
51 Flags PatternFlag
52 }
53
54
55
56
57 type RoundingContext struct {
58
59
60 MaxSignificantDigits int16
61 MaxFractionDigits int16
62
63 Increment uint32
64 IncrementScale uint8
65
66 Mode RoundingMode
67
68 DigitShift uint8
69
70
71 MinIntegerDigits uint8
72
73 MaxIntegerDigits uint8
74 MinFractionDigits uint8
75 MinSignificantDigits uint8
76
77 MinExponentDigits uint8
78 }
79
80
81
82
83 func (r *RoundingContext) RoundSignificantDigits() (n int) {
84 if r.MaxFractionDigits == 0 && r.MaxSignificantDigits > 0 {
85 return int(r.MaxSignificantDigits)
86 } else if r.isScientific() && r.MaxIntegerDigits == 1 {
87 if r.MaxSignificantDigits == 0 ||
88 int(r.MaxFractionDigits+1) == int(r.MaxSignificantDigits) {
89
90 return int(r.MaxFractionDigits) + 1
91 }
92 }
93 return -1
94 }
95
96
97
98
99 func (r *RoundingContext) RoundFractionDigits() (n int) {
100 if r.MinExponentDigits == 0 &&
101 r.MaxSignificantDigits == 0 &&
102 r.MaxFractionDigits >= 0 {
103 return int(r.MaxFractionDigits) + int(r.DigitShift)
104 }
105 return -1
106 }
107
108
109 func (r *RoundingContext) SetScale(scale int) {
110 r.MinFractionDigits = uint8(scale)
111 r.MaxFractionDigits = int16(scale)
112 }
113
114 func (r *RoundingContext) SetPrecision(prec int) {
115 r.MaxSignificantDigits = int16(prec)
116 }
117
118 func (r *RoundingContext) isScientific() bool {
119 return r.MinExponentDigits > 0
120 }
121
122 func (f *Pattern) needsSep(pos int) bool {
123 p := pos - 1
124 size := int(f.GroupingSize[0])
125 if size == 0 || p == 0 {
126 return false
127 }
128 if p == size {
129 return true
130 }
131 if p -= size; p < 0 {
132 return false
133 }
134
135
136 if x := int(f.GroupingSize[1]); x != 0 {
137 size = x
138 }
139 return p%size == 0
140 }
141
142
143 type PatternFlag uint8
144
145 const (
146 AlwaysSign PatternFlag = 1 << iota
147 ElideSign
148 AlwaysExpSign
149 AlwaysDecimalSeparator
150 ParenthesisForNegative
151
152 PadAfterNumber
153 PadAfterAffix
154
155 PadBeforePrefix = 0
156 PadAfterPrefix = PadAfterAffix
157 PadBeforeSuffix = PadAfterNumber
158 PadAfterSuffix = PadAfterNumber | PadAfterAffix
159 PadMask = PadAfterNumber | PadAfterAffix
160 )
161
162 type parser struct {
163 *Pattern
164
165 leadingSharps int
166
167 pos int
168 err error
169 doNotTerminate bool
170 groupingCount uint
171 hasGroup bool
172 buf []byte
173 }
174
175 func (p *parser) setError(err error) {
176 if p.err == nil {
177 p.err = err
178 }
179 }
180
181 func (p *parser) updateGrouping() {
182 if p.hasGroup &&
183 0 < p.groupingCount && p.groupingCount < 255 {
184 p.GroupingSize[1] = p.GroupingSize[0]
185 p.GroupingSize[0] = uint8(p.groupingCount)
186 }
187 p.groupingCount = 0
188 p.hasGroup = true
189 }
190
191 var (
192
193 errMultiplePadSpecifiers = errors.New("format: pattern has multiple pad specifiers")
194 errInvalidPadSpecifier = errors.New("format: invalid pad specifier")
195 errInvalidQuote = errors.New("format: invalid quote")
196 errAffixTooLarge = errors.New("format: prefix or suffix exceeds maximum UTF-8 length of 256 bytes")
197 errDuplicatePercentSign = errors.New("format: duplicate percent sign")
198 errDuplicatePermilleSign = errors.New("format: duplicate permille sign")
199 errUnexpectedEnd = errors.New("format: unexpected end of pattern")
200 )
201
202
203
204
205 func ParsePattern(s string) (f *Pattern, err error) {
206 p := parser{Pattern: &Pattern{}}
207
208 s = p.parseSubPattern(s)
209
210 if s != "" {
211
212 if s[0] != ';' {
213 p.setError(errors.New("format: error parsing first sub pattern"))
214 return nil, p.err
215 }
216 neg := parser{Pattern: &Pattern{}}
217 s = neg.parseSubPattern(s[len(";"):])
218 p.NegOffset = uint16(len(p.buf))
219 p.buf = append(p.buf, neg.buf...)
220 }
221 if s != "" {
222 p.setError(errors.New("format: spurious characters at end of pattern"))
223 }
224 if p.err != nil {
225 return nil, p.err
226 }
227 if affix := string(p.buf); affix == "\x00\x00" || affix == "\x00\x00\x00\x00" {
228
229 p.NegOffset = 0
230 } else {
231 p.Affix = affix
232 }
233 if p.Increment == 0 {
234 p.IncrementScale = 0
235 }
236 return p.Pattern, nil
237 }
238
239 func (p *parser) parseSubPattern(s string) string {
240 s = p.parsePad(s, PadBeforePrefix)
241 s = p.parseAffix(s)
242 s = p.parsePad(s, PadAfterPrefix)
243
244 s = p.parse(p.number, s)
245 p.updateGrouping()
246
247 s = p.parsePad(s, PadBeforeSuffix)
248 s = p.parseAffix(s)
249 s = p.parsePad(s, PadAfterSuffix)
250 return s
251 }
252
253 func (p *parser) parsePad(s string, f PatternFlag) (tail string) {
254 if len(s) >= 2 && s[0] == '*' {
255 r, sz := utf8.DecodeRuneInString(s[1:])
256 if p.PadRune != 0 {
257 p.err = errMultiplePadSpecifiers
258 } else {
259 p.Flags |= f
260 p.PadRune = r
261 }
262 return s[1+sz:]
263 }
264 return s
265 }
266
267 func (p *parser) parseAffix(s string) string {
268 x := len(p.buf)
269 p.buf = append(p.buf, 0)
270
271 s = p.parse(p.affix, s)
272
273 n := len(p.buf) - x - 1
274 if n > 0xFF {
275 p.setError(errAffixTooLarge)
276 }
277 p.buf[x] = uint8(n)
278 return s
279 }
280
281
282
283
284 type state func(r rune) state
285
286
287
288 func (p *parser) parse(fn state, s string) (tail string) {
289 for i, r := range s {
290 p.doNotTerminate = false
291 if fn = fn(r); fn == nil || p.err != nil {
292 return s[i:]
293 }
294 p.FormatWidth++
295 }
296 if p.doNotTerminate {
297 p.setError(errUnexpectedEnd)
298 }
299 return ""
300 }
301
302 func (p *parser) affix(r rune) state {
303 switch r {
304 case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
305 '#', '@', '.', '*', ',', ';':
306 return nil
307 case '\'':
308 p.FormatWidth--
309 return p.escapeFirst
310 case '%':
311 if p.DigitShift != 0 {
312 p.setError(errDuplicatePercentSign)
313 }
314 p.DigitShift = 2
315 case '\u2030':
316 if p.DigitShift != 0 {
317 p.setError(errDuplicatePermilleSign)
318 }
319 p.DigitShift = 3
320
321 }
322 p.buf = append(p.buf, string(r)...)
323 return p.affix
324 }
325
326 func (p *parser) escapeFirst(r rune) state {
327 switch r {
328 case '\'':
329 p.buf = append(p.buf, "\\'"...)
330 return p.affix
331 default:
332 p.buf = append(p.buf, '\'')
333 p.buf = append(p.buf, string(r)...)
334 }
335 return p.escape
336 }
337
338 func (p *parser) escape(r rune) state {
339 switch r {
340 case '\'':
341 p.FormatWidth--
342 p.buf = append(p.buf, '\'')
343 return p.affix
344 default:
345 p.buf = append(p.buf, string(r)...)
346 }
347 return p.escape
348 }
349
350
351
352
353 func (p *parser) number(r rune) state {
354 switch r {
355 case '#':
356 p.groupingCount++
357 p.leadingSharps++
358 case '@':
359 p.groupingCount++
360 p.leadingSharps = 0
361 p.MaxFractionDigits = -1
362 return p.sigDigits(r)
363 case ',':
364 if p.leadingSharps == 0 {
365 return nil
366 }
367 p.updateGrouping()
368 case 'E':
369 p.MaxIntegerDigits = uint8(p.leadingSharps)
370 return p.exponent
371 case '.':
372 p.updateGrouping()
373 return p.fraction
374 case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
375 return p.integer(r)
376 default:
377 return nil
378 }
379 return p.number
380 }
381
382 func (p *parser) integer(r rune) state {
383 if !('0' <= r && r <= '9') {
384 var next state
385 switch r {
386 case 'E':
387 if p.leadingSharps > 0 {
388 p.MaxIntegerDigits = uint8(p.leadingSharps) + p.MinIntegerDigits
389 }
390 next = p.exponent
391 case '.':
392 next = p.fraction
393 case ',':
394 next = p.integer
395 }
396 p.updateGrouping()
397 return next
398 }
399 p.Increment = p.Increment*10 + uint32(r-'0')
400 p.groupingCount++
401 p.MinIntegerDigits++
402 return p.integer
403 }
404
405 func (p *parser) sigDigits(r rune) state {
406 switch r {
407 case '@':
408 p.groupingCount++
409 p.MaxSignificantDigits++
410 p.MinSignificantDigits++
411 case '#':
412 return p.sigDigitsFinal(r)
413 case 'E':
414 p.updateGrouping()
415 return p.normalizeSigDigitsWithExponent()
416 default:
417 p.updateGrouping()
418 return nil
419 }
420 return p.sigDigits
421 }
422
423 func (p *parser) sigDigitsFinal(r rune) state {
424 switch r {
425 case '#':
426 p.groupingCount++
427 p.MaxSignificantDigits++
428 case 'E':
429 p.updateGrouping()
430 return p.normalizeSigDigitsWithExponent()
431 default:
432 p.updateGrouping()
433 return nil
434 }
435 return p.sigDigitsFinal
436 }
437
438 func (p *parser) normalizeSigDigitsWithExponent() state {
439 p.MinIntegerDigits, p.MaxIntegerDigits = 1, 1
440 p.MinFractionDigits = p.MinSignificantDigits - 1
441 p.MaxFractionDigits = p.MaxSignificantDigits - 1
442 p.MinSignificantDigits, p.MaxSignificantDigits = 0, 0
443 return p.exponent
444 }
445
446 func (p *parser) fraction(r rune) state {
447 switch r {
448 case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
449 p.Increment = p.Increment*10 + uint32(r-'0')
450 p.IncrementScale++
451 p.MinFractionDigits++
452 p.MaxFractionDigits++
453 case '#':
454 p.MaxFractionDigits++
455 case 'E':
456 if p.leadingSharps > 0 {
457 p.MaxIntegerDigits = uint8(p.leadingSharps) + p.MinIntegerDigits
458 }
459 return p.exponent
460 default:
461 return nil
462 }
463 return p.fraction
464 }
465
466 func (p *parser) exponent(r rune) state {
467 switch r {
468 case '+':
469
470 if p.Flags&AlwaysExpSign != 0 || p.MinExponentDigits > 0 {
471 break
472 }
473 p.Flags |= AlwaysExpSign
474 p.doNotTerminate = true
475 return p.exponent
476 case '0':
477 p.MinExponentDigits++
478 return p.exponent
479 }
480
481 if p.MinExponentDigits == 0 {
482 p.setError(errors.New("format: need at least one digit"))
483 }
484 return nil
485 }
486
View as plain text