summaryrefslogtreecommitdiff
path: root/vendor/golang.org/x/text/internal/number/pattern.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/golang.org/x/text/internal/number/pattern.go')
-rw-r--r--vendor/golang.org/x/text/internal/number/pattern.go485
1 files changed, 0 insertions, 485 deletions
diff --git a/vendor/golang.org/x/text/internal/number/pattern.go b/vendor/golang.org/x/text/internal/number/pattern.go
deleted file mode 100644
index b95ca40..0000000
--- a/vendor/golang.org/x/text/internal/number/pattern.go
+++ /dev/null
@@ -1,485 +0,0 @@
-// Copyright 2015 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package number
-
-import (
- "errors"
- "unicode/utf8"
-)
-
-// This file contains a parser for the CLDR number patterns as described in
-// http://unicode.org/reports/tr35/tr35-numbers.html#Number_Format_Patterns.
-//
-// The following BNF is derived from this standard.
-//
-// pattern := subpattern (';' subpattern)?
-// subpattern := affix? number exponent? affix?
-// number := decimal | sigDigits
-// decimal := '#'* '0'* ('.' fraction)? | '#' | '0'
-// fraction := '0'* '#'*
-// sigDigits := '#'* '@' '@'* '#'*
-// exponent := 'E' '+'? '0'* '0'
-// padSpec := '*' \L
-//
-// Notes:
-// - An affix pattern may contain any runes, but runes with special meaning
-// should be escaped.
-// - Sequences of digits, '#', and '@' in decimal and sigDigits may have
-// interstitial commas.
-
-// TODO: replace special characters in affixes (-, +, ¤) with control codes.
-
-// Pattern holds information for formatting numbers. It is designed to hold
-// information from CLDR number patterns.
-//
-// This pattern is precompiled for all patterns for all languages. Even though
-// the number of patterns is not very large, we want to keep this small.
-//
-// This type is only intended for internal use.
-type Pattern struct {
- RoundingContext
-
- Affix string // includes prefix and suffix. First byte is prefix length.
- Offset uint16 // Offset into Affix for prefix and suffix
- NegOffset uint16 // Offset into Affix for negative prefix and suffix or 0.
- PadRune rune
- FormatWidth uint16
-
- GroupingSize [2]uint8
- Flags PatternFlag
-}
-
-// A RoundingContext indicates how a number should be converted to digits.
-// It contains all information needed to determine the "visible digits" as
-// required by the pluralization rules.
-type RoundingContext struct {
- // TODO: unify these two fields so that there is a more unambiguous meaning
- // of how precision is handled.
- MaxSignificantDigits int16 // -1 is unlimited
- MaxFractionDigits int16 // -1 is unlimited
-
- Increment uint32
- IncrementScale uint8 // May differ from printed scale.
-
- Mode RoundingMode
-
- DigitShift uint8 // Number of decimals to shift. Used for % and ‰.
-
- // Number of digits.
- MinIntegerDigits uint8
-
- MaxIntegerDigits uint8
- MinFractionDigits uint8
- MinSignificantDigits uint8
-
- MinExponentDigits uint8
-}
-
-// RoundSignificantDigits returns the number of significant digits an
-// implementation of Convert may round to or n < 0 if there is no maximum or
-// a maximum is not recommended.
-func (r *RoundingContext) RoundSignificantDigits() (n int) {
- if r.MaxFractionDigits == 0 && r.MaxSignificantDigits > 0 {
- return int(r.MaxSignificantDigits)
- } else if r.isScientific() && r.MaxIntegerDigits == 1 {
- if r.MaxSignificantDigits == 0 ||
- int(r.MaxFractionDigits+1) == int(r.MaxSignificantDigits) {
- // Note: don't add DigitShift: it is only used for decimals.
- return int(r.MaxFractionDigits) + 1
- }
- }
- return -1
-}
-
-// RoundFractionDigits returns the number of fraction digits an implementation
-// of Convert may round to or n < 0 if there is no maximum or a maximum is not
-// recommended.
-func (r *RoundingContext) RoundFractionDigits() (n int) {
- if r.MinExponentDigits == 0 &&
- r.MaxSignificantDigits == 0 &&
- r.MaxFractionDigits >= 0 {
- return int(r.MaxFractionDigits) + int(r.DigitShift)
- }
- return -1
-}
-
-// SetScale fixes the RoundingContext to a fixed number of fraction digits.
-func (r *RoundingContext) SetScale(scale int) {
- r.MinFractionDigits = uint8(scale)
- r.MaxFractionDigits = int16(scale)
-}
-
-func (r *RoundingContext) SetPrecision(prec int) {
- r.MaxSignificantDigits = int16(prec)
-}
-
-func (r *RoundingContext) isScientific() bool {
- return r.MinExponentDigits > 0
-}
-
-func (f *Pattern) needsSep(pos int) bool {
- p := pos - 1
- size := int(f.GroupingSize[0])
- if size == 0 || p == 0 {
- return false
- }
- if p == size {
- return true
- }
- if p -= size; p < 0 {
- return false
- }
- // TODO: make second groupingsize the same as first if 0 so that we can
- // avoid this check.
- if x := int(f.GroupingSize[1]); x != 0 {
- size = x
- }
- return p%size == 0
-}
-
-// A PatternFlag is a bit mask for the flag field of a Pattern.
-type PatternFlag uint8
-
-const (
- AlwaysSign PatternFlag = 1 << iota
- ElideSign // Use space instead of plus sign. AlwaysSign must be true.
- AlwaysExpSign
- AlwaysDecimalSeparator
- ParenthesisForNegative // Common pattern. Saves space.
-
- PadAfterNumber
- PadAfterAffix
-
- PadBeforePrefix = 0 // Default
- PadAfterPrefix = PadAfterAffix
- PadBeforeSuffix = PadAfterNumber
- PadAfterSuffix = PadAfterNumber | PadAfterAffix
- PadMask = PadAfterNumber | PadAfterAffix
-)
-
-type parser struct {
- *Pattern
-
- leadingSharps int
-
- pos int
- err error
- doNotTerminate bool
- groupingCount uint
- hasGroup bool
- buf []byte
-}
-
-func (p *parser) setError(err error) {
- if p.err == nil {
- p.err = err
- }
-}
-
-func (p *parser) updateGrouping() {
- if p.hasGroup &&
- 0 < p.groupingCount && p.groupingCount < 255 {
- p.GroupingSize[1] = p.GroupingSize[0]
- p.GroupingSize[0] = uint8(p.groupingCount)
- }
- p.groupingCount = 0
- p.hasGroup = true
-}
-
-var (
- // TODO: more sensible and localizeable error messages.
- errMultiplePadSpecifiers = errors.New("format: pattern has multiple pad specifiers")
- errInvalidPadSpecifier = errors.New("format: invalid pad specifier")
- errInvalidQuote = errors.New("format: invalid quote")
- errAffixTooLarge = errors.New("format: prefix or suffix exceeds maximum UTF-8 length of 256 bytes")
- errDuplicatePercentSign = errors.New("format: duplicate percent sign")
- errDuplicatePermilleSign = errors.New("format: duplicate permille sign")
- errUnexpectedEnd = errors.New("format: unexpected end of pattern")
-)
-
-// ParsePattern extracts formatting information from a CLDR number pattern.
-//
-// See http://unicode.org/reports/tr35/tr35-numbers.html#Number_Format_Patterns.
-func ParsePattern(s string) (f *Pattern, err error) {
- p := parser{Pattern: &Pattern{}}
-
- s = p.parseSubPattern(s)
-
- if s != "" {
- // Parse negative sub pattern.
- if s[0] != ';' {
- p.setError(errors.New("format: error parsing first sub pattern"))
- return nil, p.err
- }
- neg := parser{Pattern: &Pattern{}} // just for extracting the affixes.
- s = neg.parseSubPattern(s[len(";"):])
- p.NegOffset = uint16(len(p.buf))
- p.buf = append(p.buf, neg.buf...)
- }
- if s != "" {
- p.setError(errors.New("format: spurious characters at end of pattern"))
- }
- if p.err != nil {
- return nil, p.err
- }
- if affix := string(p.buf); affix == "\x00\x00" || affix == "\x00\x00\x00\x00" {
- // No prefix or suffixes.
- p.NegOffset = 0
- } else {
- p.Affix = affix
- }
- if p.Increment == 0 {
- p.IncrementScale = 0
- }
- return p.Pattern, nil
-}
-
-func (p *parser) parseSubPattern(s string) string {
- s = p.parsePad(s, PadBeforePrefix)
- s = p.parseAffix(s)
- s = p.parsePad(s, PadAfterPrefix)
-
- s = p.parse(p.number, s)
- p.updateGrouping()
-
- s = p.parsePad(s, PadBeforeSuffix)
- s = p.parseAffix(s)
- s = p.parsePad(s, PadAfterSuffix)
- return s
-}
-
-func (p *parser) parsePad(s string, f PatternFlag) (tail string) {
- if len(s) >= 2 && s[0] == '*' {
- r, sz := utf8.DecodeRuneInString(s[1:])
- if p.PadRune != 0 {
- p.err = errMultiplePadSpecifiers
- } else {
- p.Flags |= f
- p.PadRune = r
- }
- return s[1+sz:]
- }
- return s
-}
-
-func (p *parser) parseAffix(s string) string {
- x := len(p.buf)
- p.buf = append(p.buf, 0) // placeholder for affix length
-
- s = p.parse(p.affix, s)
-
- n := len(p.buf) - x - 1
- if n > 0xFF {
- p.setError(errAffixTooLarge)
- }
- p.buf[x] = uint8(n)
- return s
-}
-
-// state implements a state transition. It returns the new state. A state
-// function may set an error on the parser or may simply return on an incorrect
-// token and let the next phase fail.
-type state func(r rune) state
-
-// parse repeatedly applies a state function on the given string until a
-// termination condition is reached.
-func (p *parser) parse(fn state, s string) (tail string) {
- for i, r := range s {
- p.doNotTerminate = false
- if fn = fn(r); fn == nil || p.err != nil {
- return s[i:]
- }
- p.FormatWidth++
- }
- if p.doNotTerminate {
- p.setError(errUnexpectedEnd)
- }
- return ""
-}
-
-func (p *parser) affix(r rune) state {
- switch r {
- case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
- '#', '@', '.', '*', ',', ';':
- return nil
- case '\'':
- p.FormatWidth--
- return p.escapeFirst
- case '%':
- if p.DigitShift != 0 {
- p.setError(errDuplicatePercentSign)
- }
- p.DigitShift = 2
- case '\u2030': // ‰ Per mille
- if p.DigitShift != 0 {
- p.setError(errDuplicatePermilleSign)
- }
- p.DigitShift = 3
- // TODO: handle currency somehow: ¤, ¤¤, ¤¤¤, ¤¤¤¤
- }
- p.buf = append(p.buf, string(r)...)
- return p.affix
-}
-
-func (p *parser) escapeFirst(r rune) state {
- switch r {
- case '\'':
- p.buf = append(p.buf, "\\'"...)
- return p.affix
- default:
- p.buf = append(p.buf, '\'')
- p.buf = append(p.buf, string(r)...)
- }
- return p.escape
-}
-
-func (p *parser) escape(r rune) state {
- switch r {
- case '\'':
- p.FormatWidth--
- p.buf = append(p.buf, '\'')
- return p.affix
- default:
- p.buf = append(p.buf, string(r)...)
- }
- return p.escape
-}
-
-// number parses a number. The BNF says the integer part should always have
-// a '0', but that does not appear to be the case according to the rest of the
-// documentation. We will allow having only '#' numbers.
-func (p *parser) number(r rune) state {
- switch r {
- case '#':
- p.groupingCount++
- p.leadingSharps++
- case '@':
- p.groupingCount++
- p.leadingSharps = 0
- p.MaxFractionDigits = -1
- return p.sigDigits(r)
- case ',':
- if p.leadingSharps == 0 { // no leading commas
- return nil
- }
- p.updateGrouping()
- case 'E':
- p.MaxIntegerDigits = uint8(p.leadingSharps)
- return p.exponent
- case '.': // allow ".##" etc.
- p.updateGrouping()
- return p.fraction
- case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
- return p.integer(r)
- default:
- return nil
- }
- return p.number
-}
-
-func (p *parser) integer(r rune) state {
- if !('0' <= r && r <= '9') {
- var next state
- switch r {
- case 'E':
- if p.leadingSharps > 0 {
- p.MaxIntegerDigits = uint8(p.leadingSharps) + p.MinIntegerDigits
- }
- next = p.exponent
- case '.':
- next = p.fraction
- case ',':
- next = p.integer
- }
- p.updateGrouping()
- return next
- }
- p.Increment = p.Increment*10 + uint32(r-'0')
- p.groupingCount++
- p.MinIntegerDigits++
- return p.integer
-}
-
-func (p *parser) sigDigits(r rune) state {
- switch r {
- case '@':
- p.groupingCount++
- p.MaxSignificantDigits++
- p.MinSignificantDigits++
- case '#':
- return p.sigDigitsFinal(r)
- case 'E':
- p.updateGrouping()
- return p.normalizeSigDigitsWithExponent()
- default:
- p.updateGrouping()
- return nil
- }
- return p.sigDigits
-}
-
-func (p *parser) sigDigitsFinal(r rune) state {
- switch r {
- case '#':
- p.groupingCount++
- p.MaxSignificantDigits++
- case 'E':
- p.updateGrouping()
- return p.normalizeSigDigitsWithExponent()
- default:
- p.updateGrouping()
- return nil
- }
- return p.sigDigitsFinal
-}
-
-func (p *parser) normalizeSigDigitsWithExponent() state {
- p.MinIntegerDigits, p.MaxIntegerDigits = 1, 1
- p.MinFractionDigits = p.MinSignificantDigits - 1
- p.MaxFractionDigits = p.MaxSignificantDigits - 1
- p.MinSignificantDigits, p.MaxSignificantDigits = 0, 0
- return p.exponent
-}
-
-func (p *parser) fraction(r rune) state {
- switch r {
- case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
- p.Increment = p.Increment*10 + uint32(r-'0')
- p.IncrementScale++
- p.MinFractionDigits++
- p.MaxFractionDigits++
- case '#':
- p.MaxFractionDigits++
- case 'E':
- if p.leadingSharps > 0 {
- p.MaxIntegerDigits = uint8(p.leadingSharps) + p.MinIntegerDigits
- }
- return p.exponent
- default:
- return nil
- }
- return p.fraction
-}
-
-func (p *parser) exponent(r rune) state {
- switch r {
- case '+':
- // Set mode and check it wasn't already set.
- if p.Flags&AlwaysExpSign != 0 || p.MinExponentDigits > 0 {
- break
- }
- p.Flags |= AlwaysExpSign
- p.doNotTerminate = true
- return p.exponent
- case '0':
- p.MinExponentDigits++
- return p.exponent
- }
- // termination condition
- if p.MinExponentDigits == 0 {
- p.setError(errors.New("format: need at least one digit"))
- }
- return nil
-}