aboutsummaryrefslogtreecommitdiff
path: root/vendor/honnef.co/go/tools/printf/printf.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/honnef.co/go/tools/printf/printf.go')
-rw-r--r--vendor/honnef.co/go/tools/printf/printf.go197
1 files changed, 197 insertions, 0 deletions
diff --git a/vendor/honnef.co/go/tools/printf/printf.go b/vendor/honnef.co/go/tools/printf/printf.go
new file mode 100644
index 0000000..754db9b
--- /dev/null
+++ b/vendor/honnef.co/go/tools/printf/printf.go
@@ -0,0 +1,197 @@
1// Package printf implements a parser for fmt.Printf-style format
2// strings.
3//
4// It parses verbs according to the following syntax:
5// Numeric -> '0'-'9'
6// Letter -> 'a'-'z' | 'A'-'Z'
7// Index -> '[' Numeric+ ']'
8// Star -> '*'
9// Star -> Index '*'
10//
11// Precision -> Numeric+ | Star
12// Width -> Numeric+ | Star
13//
14// WidthAndPrecision -> Width '.' Precision
15// WidthAndPrecision -> Width '.'
16// WidthAndPrecision -> Width
17// WidthAndPrecision -> '.' Precision
18// WidthAndPrecision -> '.'
19//
20// Flag -> '+' | '-' | '#' | ' ' | '0'
21// Verb -> Letter | '%'
22//
23// Input -> '%' [ Flag+ ] [ WidthAndPrecision ] [ Index ] Verb
24package printf
25
26import (
27 "errors"
28 "regexp"
29 "strconv"
30 "strings"
31)
32
33// ErrInvalid is returned for invalid format strings or verbs.
34var ErrInvalid = errors.New("invalid format string")
35
36type Verb struct {
37 Letter rune
38 Flags string
39
40 Width Argument
41 Precision Argument
42 // Which value in the argument list the verb uses.
43 // -1 denotes the next argument,
44 // values > 0 denote explicit arguments.
45 // The value 0 denotes that no argument is consumed. This is the case for %%.
46 Value int
47
48 Raw string
49}
50
51// Argument is an implicit or explicit width or precision.
52type Argument interface {
53 isArgument()
54}
55
56// The Default value, when no width or precision is provided.
57type Default struct{}
58
59// Zero is the implicit zero value.
60// This value may only appear for precisions in format strings like %6.f
61type Zero struct{}
62
63// Star is a * value, which may either refer to the next argument (Index == -1) or an explicit argument.
64type Star struct{ Index int }
65
66// A Literal value, such as 6 in %6d.
67type Literal int
68
69func (Default) isArgument() {}
70func (Zero) isArgument() {}
71func (Star) isArgument() {}
72func (Literal) isArgument() {}
73
74// Parse parses f and returns a list of actions.
75// An action may either be a literal string, or a Verb.
76func Parse(f string) ([]interface{}, error) {
77 var out []interface{}
78 for len(f) > 0 {
79 if f[0] == '%' {
80 v, n, err := ParseVerb(f)
81 if err != nil {
82 return nil, err
83 }
84 f = f[n:]
85 out = append(out, v)
86 } else {
87 n := strings.IndexByte(f, '%')
88 if n > -1 {
89 out = append(out, f[:n])
90 f = f[n:]
91 } else {
92 out = append(out, f)
93 f = ""
94 }
95 }
96 }
97
98 return out, nil
99}
100
101func atoi(s string) int {
102 n, _ := strconv.Atoi(s)
103 return n
104}
105
106// ParseVerb parses the verb at the beginning of f.
107// It returns the verb, how much of the input was consumed, and an error, if any.
108func ParseVerb(f string) (Verb, int, error) {
109 if len(f) < 2 {
110 return Verb{}, 0, ErrInvalid
111 }
112 const (
113 flags = 1
114
115 width = 2
116 widthStar = 3
117 widthIndex = 5
118
119 dot = 6
120 prec = 7
121 precStar = 8
122 precIndex = 10
123
124 verbIndex = 11
125 verb = 12
126 )
127
128 m := re.FindStringSubmatch(f)
129 if m == nil {
130 return Verb{}, 0, ErrInvalid
131 }
132
133 v := Verb{
134 Letter: []rune(m[verb])[0],
135 Flags: m[flags],
136 Raw: m[0],
137 }
138
139 if m[width] != "" {
140 // Literal width
141 v.Width = Literal(atoi(m[width]))
142 } else if m[widthStar] != "" {
143 // Star width
144 if m[widthIndex] != "" {
145 v.Width = Star{atoi(m[widthIndex])}
146 } else {
147 v.Width = Star{-1}
148 }
149 } else {
150 // Default width
151 v.Width = Default{}
152 }
153
154 if m[dot] == "" {
155 // default precision
156 v.Precision = Default{}
157 } else {
158 if m[prec] != "" {
159 // Literal precision
160 v.Precision = Literal(atoi(m[prec]))
161 } else if m[precStar] != "" {
162 // Star precision
163 if m[precIndex] != "" {
164 v.Precision = Star{atoi(m[precIndex])}
165 } else {
166 v.Precision = Star{-1}
167 }
168 } else {
169 // Zero precision
170 v.Precision = Zero{}
171 }
172 }
173
174 if m[verb] == "%" {
175 v.Value = 0
176 } else if m[verbIndex] != "" {
177 v.Value = atoi(m[verbIndex])
178 } else {
179 v.Value = -1
180 }
181
182 return v, len(m[0]), nil
183}
184
185const (
186 flags = `([+#0 -]*)`
187 verb = `([a-zA-Z%])`
188 index = `(?:\[([0-9]+)\])`
189 star = `((` + index + `)?\*)`
190 width1 = `([0-9]+)`
191 width2 = star
192 width = `(?:` + width1 + `|` + width2 + `)`
193 precision = width
194 widthAndPrecision = `(?:(?:` + width + `)?(?:(\.)(?:` + precision + `)?)?)`
195)
196
197var re = regexp.MustCompile(`^%` + flags + widthAndPrecision + `?` + index + `?` + verb)