diff options
Diffstat (limited to 'vendor/golang.org/x/text/internal')
| -rw-r--r-- | vendor/golang.org/x/text/internal/format/format.go | 41 | ||||
| -rw-r--r-- | vendor/golang.org/x/text/internal/format/parser.go | 358 | 
2 files changed, 399 insertions, 0 deletions
diff --git a/vendor/golang.org/x/text/internal/format/format.go b/vendor/golang.org/x/text/internal/format/format.go new file mode 100644 index 000000000..ee1c57a3c --- /dev/null +++ b/vendor/golang.org/x/text/internal/format/format.go @@ -0,0 +1,41 @@ +// 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 format contains types for defining language-specific formatting of +// values. +// +// This package is internal now, but will eventually be exposed after the API +// settles. +package format // import "golang.org/x/text/internal/format" + +import ( +	"fmt" + +	"golang.org/x/text/language" +) + +// State represents the printer state passed to custom formatters. It provides +// access to the fmt.State interface and the sentence and language-related +// context. +type State interface { +	fmt.State + +	// Language reports the requested language in which to render a message. +	Language() language.Tag + +	// TODO: consider this and removing rune from the Format method in the +	// Formatter interface. +	// +	// Verb returns the format variant to render, analogous to the types used +	// in fmt. Use 'v' for the default or only variant. +	// Verb() rune + +	// TODO: more info: +	// - sentence context such as linguistic features passed by the translator. +} + +// Formatter is analogous to fmt.Formatter. +type Formatter interface { +	Format(state State, verb rune) +} diff --git a/vendor/golang.org/x/text/internal/format/parser.go b/vendor/golang.org/x/text/internal/format/parser.go new file mode 100644 index 000000000..855aed71d --- /dev/null +++ b/vendor/golang.org/x/text/internal/format/parser.go @@ -0,0 +1,358 @@ +// Copyright 2017 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 format + +import ( +	"reflect" +	"unicode/utf8" +) + +// A Parser parses a format string. The result from the parse are set in the +// struct fields. +type Parser struct { +	Verb rune + +	WidthPresent bool +	PrecPresent  bool +	Minus        bool +	Plus         bool +	Sharp        bool +	Space        bool +	Zero         bool + +	// For the formats %+v %#v, we set the plusV/sharpV flags +	// and clear the plus/sharp flags since %+v and %#v are in effect +	// different, flagless formats set at the top level. +	PlusV  bool +	SharpV bool + +	HasIndex bool + +	Width int +	Prec  int // precision + +	// retain arguments across calls. +	Args []interface{} +	// retain current argument number across calls +	ArgNum int + +	// reordered records whether the format string used argument reordering. +	Reordered bool +	// goodArgNum records whether the most recent reordering directive was valid. +	goodArgNum bool + +	// position info +	format   string +	startPos int +	endPos   int +	Status   Status +} + +// Reset initializes a parser to scan format strings for the given args. +func (p *Parser) Reset(args []interface{}) { +	p.Args = args +	p.ArgNum = 0 +	p.startPos = 0 +	p.Reordered = false +} + +// Text returns the part of the format string that was parsed by the last call +// to Scan. It returns the original substitution clause if the current scan +// parsed a substitution. +func (p *Parser) Text() string { return p.format[p.startPos:p.endPos] } + +// SetFormat sets a new format string to parse. It does not reset the argument +// count. +func (p *Parser) SetFormat(format string) { +	p.format = format +	p.startPos = 0 +	p.endPos = 0 +} + +// Status indicates the result type of a call to Scan. +type Status int + +const ( +	StatusText Status = iota +	StatusSubstitution +	StatusBadWidthSubstitution +	StatusBadPrecSubstitution +	StatusNoVerb +	StatusBadArgNum +	StatusMissingArg +) + +// ClearFlags reset the parser to default behavior. +func (p *Parser) ClearFlags() { +	p.WidthPresent = false +	p.PrecPresent = false +	p.Minus = false +	p.Plus = false +	p.Sharp = false +	p.Space = false +	p.Zero = false + +	p.PlusV = false +	p.SharpV = false + +	p.HasIndex = false +} + +// Scan scans the next part of the format string and sets the status to +// indicate whether it scanned a string literal, substitution or error. +func (p *Parser) Scan() bool { +	p.Status = StatusText +	format := p.format +	end := len(format) +	if p.endPos >= end { +		return false +	} +	afterIndex := false // previous item in format was an index like [3]. + +	p.startPos = p.endPos +	p.goodArgNum = true +	i := p.startPos +	for i < end && format[i] != '%' { +		i++ +	} +	if i > p.startPos { +		p.endPos = i +		return true +	} +	// Process one verb +	i++ + +	p.Status = StatusSubstitution + +	// Do we have flags? +	p.ClearFlags() + +simpleFormat: +	for ; i < end; i++ { +		c := p.format[i] +		switch c { +		case '#': +			p.Sharp = true +		case '0': +			p.Zero = !p.Minus // Only allow zero padding to the left. +		case '+': +			p.Plus = true +		case '-': +			p.Minus = true +			p.Zero = false // Do not pad with zeros to the right. +		case ' ': +			p.Space = true +		default: +			// Fast path for common case of ascii lower case simple verbs +			// without precision or width or argument indices. +			if 'a' <= c && c <= 'z' && p.ArgNum < len(p.Args) { +				if c == 'v' { +					// Go syntax +					p.SharpV = p.Sharp +					p.Sharp = false +					// Struct-field syntax +					p.PlusV = p.Plus +					p.Plus = false +				} +				p.Verb = rune(c) +				p.ArgNum++ +				p.endPos = i + 1 +				return true +			} +			// Format is more complex than simple flags and a verb or is malformed. +			break simpleFormat +		} +	} + +	// Do we have an explicit argument index? +	i, afterIndex = p.updateArgNumber(format, i) + +	// Do we have width? +	if i < end && format[i] == '*' { +		i++ +		p.Width, p.WidthPresent = p.intFromArg() + +		if !p.WidthPresent { +			p.Status = StatusBadWidthSubstitution +		} + +		// We have a negative width, so take its value and ensure +		// that the minus flag is set +		if p.Width < 0 { +			p.Width = -p.Width +			p.Minus = true +			p.Zero = false // Do not pad with zeros to the right. +		} +		afterIndex = false +	} else { +		p.Width, p.WidthPresent, i = parsenum(format, i, end) +		if afterIndex && p.WidthPresent { // "%[3]2d" +			p.goodArgNum = false +		} +	} + +	// Do we have precision? +	if i+1 < end && format[i] == '.' { +		i++ +		if afterIndex { // "%[3].2d" +			p.goodArgNum = false +		} +		i, afterIndex = p.updateArgNumber(format, i) +		if i < end && format[i] == '*' { +			i++ +			p.Prec, p.PrecPresent = p.intFromArg() +			// Negative precision arguments don't make sense +			if p.Prec < 0 { +				p.Prec = 0 +				p.PrecPresent = false +			} +			if !p.PrecPresent { +				p.Status = StatusBadPrecSubstitution +			} +			afterIndex = false +		} else { +			p.Prec, p.PrecPresent, i = parsenum(format, i, end) +			if !p.PrecPresent { +				p.Prec = 0 +				p.PrecPresent = true +			} +		} +	} + +	if !afterIndex { +		i, afterIndex = p.updateArgNumber(format, i) +	} +	p.HasIndex = afterIndex + +	if i >= end { +		p.endPos = i +		p.Status = StatusNoVerb +		return true +	} + +	verb, w := utf8.DecodeRuneInString(format[i:]) +	p.endPos = i + w +	p.Verb = verb + +	switch { +	case verb == '%': // Percent does not absorb operands and ignores f.wid and f.prec. +		p.startPos = p.endPos - 1 +		p.Status = StatusText +	case !p.goodArgNum: +		p.Status = StatusBadArgNum +	case p.ArgNum >= len(p.Args): // No argument left over to print for the current verb. +		p.Status = StatusMissingArg +		p.ArgNum++ +	case verb == 'v': +		// Go syntax +		p.SharpV = p.Sharp +		p.Sharp = false +		// Struct-field syntax +		p.PlusV = p.Plus +		p.Plus = false +		fallthrough +	default: +		p.ArgNum++ +	} +	return true +} + +// intFromArg gets the ArgNumth element of Args. On return, isInt reports +// whether the argument has integer type. +func (p *Parser) intFromArg() (num int, isInt bool) { +	if p.ArgNum < len(p.Args) { +		arg := p.Args[p.ArgNum] +		num, isInt = arg.(int) // Almost always OK. +		if !isInt { +			// Work harder. +			switch v := reflect.ValueOf(arg); v.Kind() { +			case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: +				n := v.Int() +				if int64(int(n)) == n { +					num = int(n) +					isInt = true +				} +			case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: +				n := v.Uint() +				if int64(n) >= 0 && uint64(int(n)) == n { +					num = int(n) +					isInt = true +				} +			default: +				// Already 0, false. +			} +		} +		p.ArgNum++ +		if tooLarge(num) { +			num = 0 +			isInt = false +		} +	} +	return +} + +// parseArgNumber returns the value of the bracketed number, minus 1 +// (explicit argument numbers are one-indexed but we want zero-indexed). +// The opening bracket is known to be present at format[0]. +// The returned values are the index, the number of bytes to consume +// up to the closing paren, if present, and whether the number parsed +// ok. The bytes to consume will be 1 if no closing paren is present. +func parseArgNumber(format string) (index int, wid int, ok bool) { +	// There must be at least 3 bytes: [n]. +	if len(format) < 3 { +		return 0, 1, false +	} + +	// Find closing bracket. +	for i := 1; i < len(format); i++ { +		if format[i] == ']' { +			width, ok, newi := parsenum(format, 1, i) +			if !ok || newi != i { +				return 0, i + 1, false +			} +			return width - 1, i + 1, true // arg numbers are one-indexed and skip paren. +		} +	} +	return 0, 1, false +} + +// updateArgNumber returns the next argument to evaluate, which is either the value of the passed-in +// argNum or the value of the bracketed integer that begins format[i:]. It also returns +// the new value of i, that is, the index of the next byte of the format to process. +func (p *Parser) updateArgNumber(format string, i int) (newi int, found bool) { +	if len(format) <= i || format[i] != '[' { +		return i, false +	} +	p.Reordered = true +	index, wid, ok := parseArgNumber(format[i:]) +	if ok && 0 <= index && index < len(p.Args) { +		p.ArgNum = index +		return i + wid, true +	} +	p.goodArgNum = false +	return i + wid, ok +} + +// tooLarge reports whether the magnitude of the integer is +// too large to be used as a formatting width or precision. +func tooLarge(x int) bool { +	const max int = 1e6 +	return x > max || x < -max +} + +// parsenum converts ASCII to integer.  num is 0 (and isnum is false) if no number present. +func parsenum(s string, start, end int) (num int, isnum bool, newi int) { +	if start >= end { +		return 0, false, end +	} +	for newi = start; newi < end && '0' <= s[newi] && s[newi] <= '9'; newi++ { +		if tooLarge(num) { +			return 0, false, end // Overflow; crazy long number most likely. +		} +		num = num*10 + int(s[newi]-'0') +		isnum = true +	} +	return +}  | 
