Giant blob of minor changes
[dotfiles/.git] / .config / coc / extensions / coc-go-data / tools / pkg / mod / honnef.co / go / tools@v0.0.1-2020.1.5 / printf / printf.go
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
24 package printf
25
26 import (
27         "errors"
28         "regexp"
29         "strconv"
30         "strings"
31 )
32
33 // ErrInvalid is returned for invalid format strings or verbs.
34 var ErrInvalid = errors.New("invalid format string")
35
36 type 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.
52 type Argument interface {
53         isArgument()
54 }
55
56 // The Default value, when no width or precision is provided.
57 type Default struct{}
58
59 // Zero is the implicit zero value.
60 // This value may only appear for precisions in format strings like %6.f
61 type Zero struct{}
62
63 // Star is a * value, which may either refer to the next argument (Index == -1) or an explicit argument.
64 type Star struct{ Index int }
65
66 // A Literal value, such as 6 in %6d.
67 type Literal int
68
69 func (Default) isArgument() {}
70 func (Zero) isArgument()    {}
71 func (Star) isArgument()    {}
72 func (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.
76 func 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
101 func 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.
108 func 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
185 const (
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
197 var re = regexp.MustCompile(`^%` + flags + widthAndPrecision + `?` + index + `?` + verb)