podman

Форк
0
279 строк · 8.1 Кб
1
package toml
2

3
import (
4
	"fmt"
5
	"strings"
6
)
7

8
// ParseError is returned when there is an error parsing the TOML syntax such as
9
// invalid syntax, duplicate keys, etc.
10
//
11
// In addition to the error message itself, you can also print detailed location
12
// information with context by using [ErrorWithPosition]:
13
//
14
//	toml: error: Key 'fruit' was already created and cannot be used as an array.
15
//
16
//	At line 4, column 2-7:
17
//
18
//	      2 | fruit = []
19
//	      3 |
20
//	      4 | [[fruit]] # Not allowed
21
//	            ^^^^^
22
//
23
// [ErrorWithUsage] can be used to print the above with some more detailed usage
24
// guidance:
25
//
26
//	toml: error: newlines not allowed within inline tables
27
//
28
//	At line 1, column 18:
29
//
30
//	      1 | x = [{ key = 42 #
31
//	                           ^
32
//
33
//	Error help:
34
//
35
//	  Inline tables must always be on a single line:
36
//
37
//	      table = {key = 42, second = 43}
38
//
39
//	  It is invalid to split them over multiple lines like so:
40
//
41
//	      # INVALID
42
//	      table = {
43
//	          key    = 42,
44
//	          second = 43
45
//	      }
46
//
47
//	  Use regular for this:
48
//
49
//	      [table]
50
//	      key    = 42
51
//	      second = 43
52
type ParseError struct {
53
	Message  string   // Short technical message.
54
	Usage    string   // Longer message with usage guidance; may be blank.
55
	Position Position // Position of the error
56
	LastKey  string   // Last parsed key, may be blank.
57

58
	// Line the error occurred.
59
	//
60
	// Deprecated: use [Position].
61
	Line int
62

63
	err   error
64
	input string
65
}
66

67
// Position of an error.
68
type Position struct {
69
	Line  int // Line number, starting at 1.
70
	Start int // Start of error, as byte offset starting at 0.
71
	Len   int // Lenght in bytes.
72
}
73

74
func (pe ParseError) Error() string {
75
	msg := pe.Message
76
	if msg == "" { // Error from errorf()
77
		msg = pe.err.Error()
78
	}
79

80
	if pe.LastKey == "" {
81
		return fmt.Sprintf("toml: line %d: %s", pe.Position.Line, msg)
82
	}
83
	return fmt.Sprintf("toml: line %d (last key %q): %s",
84
		pe.Position.Line, pe.LastKey, msg)
85
}
86

87
// ErrorWithPosition returns the error with detailed location context.
88
//
89
// See the documentation on [ParseError].
90
func (pe ParseError) ErrorWithPosition() string {
91
	if pe.input == "" { // Should never happen, but just in case.
92
		return pe.Error()
93
	}
94

95
	var (
96
		lines = strings.Split(pe.input, "\n")
97
		col   = pe.column(lines)
98
		b     = new(strings.Builder)
99
	)
100

101
	msg := pe.Message
102
	if msg == "" {
103
		msg = pe.err.Error()
104
	}
105

106
	// TODO: don't show control characters as literals? This may not show up
107
	// well everywhere.
108

109
	if pe.Position.Len == 1 {
110
		fmt.Fprintf(b, "toml: error: %s\n\nAt line %d, column %d:\n\n",
111
			msg, pe.Position.Line, col+1)
112
	} else {
113
		fmt.Fprintf(b, "toml: error: %s\n\nAt line %d, column %d-%d:\n\n",
114
			msg, pe.Position.Line, col, col+pe.Position.Len)
115
	}
116
	if pe.Position.Line > 2 {
117
		fmt.Fprintf(b, "% 7d | %s\n", pe.Position.Line-2, lines[pe.Position.Line-3])
118
	}
119
	if pe.Position.Line > 1 {
120
		fmt.Fprintf(b, "% 7d | %s\n", pe.Position.Line-1, lines[pe.Position.Line-2])
121
	}
122
	fmt.Fprintf(b, "% 7d | %s\n", pe.Position.Line, lines[pe.Position.Line-1])
123
	fmt.Fprintf(b, "% 10s%s%s\n", "", strings.Repeat(" ", col), strings.Repeat("^", pe.Position.Len))
124
	return b.String()
125
}
126

127
// ErrorWithUsage returns the error with detailed location context and usage
128
// guidance.
129
//
130
// See the documentation on [ParseError].
131
func (pe ParseError) ErrorWithUsage() string {
132
	m := pe.ErrorWithPosition()
133
	if u, ok := pe.err.(interface{ Usage() string }); ok && u.Usage() != "" {
134
		lines := strings.Split(strings.TrimSpace(u.Usage()), "\n")
135
		for i := range lines {
136
			if lines[i] != "" {
137
				lines[i] = "    " + lines[i]
138
			}
139
		}
140
		return m + "Error help:\n\n" + strings.Join(lines, "\n") + "\n"
141
	}
142
	return m
143
}
144

145
func (pe ParseError) column(lines []string) int {
146
	var pos, col int
147
	for i := range lines {
148
		ll := len(lines[i]) + 1 // +1 for the removed newline
149
		if pos+ll >= pe.Position.Start {
150
			col = pe.Position.Start - pos
151
			if col < 0 { // Should never happen, but just in case.
152
				col = 0
153
			}
154
			break
155
		}
156
		pos += ll
157
	}
158

159
	return col
160
}
161

162
type (
163
	errLexControl       struct{ r rune }
164
	errLexEscape        struct{ r rune }
165
	errLexUTF8          struct{ b byte }
166
	errLexInvalidNum    struct{ v string }
167
	errLexInvalidDate   struct{ v string }
168
	errLexInlineTableNL struct{}
169
	errLexStringNL      struct{}
170
	errParseRange       struct {
171
		i    interface{} // int or float
172
		size string      // "int64", "uint16", etc.
173
	}
174
	errParseDuration struct{ d string }
175
)
176

177
func (e errLexControl) Error() string {
178
	return fmt.Sprintf("TOML files cannot contain control characters: '0x%02x'", e.r)
179
}
180
func (e errLexControl) Usage() string { return "" }
181

182
func (e errLexEscape) Error() string        { return fmt.Sprintf(`invalid escape in string '\%c'`, e.r) }
183
func (e errLexEscape) Usage() string        { return usageEscape }
184
func (e errLexUTF8) Error() string          { return fmt.Sprintf("invalid UTF-8 byte: 0x%02x", e.b) }
185
func (e errLexUTF8) Usage() string          { return "" }
186
func (e errLexInvalidNum) Error() string    { return fmt.Sprintf("invalid number: %q", e.v) }
187
func (e errLexInvalidNum) Usage() string    { return "" }
188
func (e errLexInvalidDate) Error() string   { return fmt.Sprintf("invalid date: %q", e.v) }
189
func (e errLexInvalidDate) Usage() string   { return "" }
190
func (e errLexInlineTableNL) Error() string { return "newlines not allowed within inline tables" }
191
func (e errLexInlineTableNL) Usage() string { return usageInlineNewline }
192
func (e errLexStringNL) Error() string      { return "strings cannot contain newlines" }
193
func (e errLexStringNL) Usage() string      { return usageStringNewline }
194
func (e errParseRange) Error() string       { return fmt.Sprintf("%v is out of range for %s", e.i, e.size) }
195
func (e errParseRange) Usage() string       { return usageIntOverflow }
196
func (e errParseDuration) Error() string    { return fmt.Sprintf("invalid duration: %q", e.d) }
197
func (e errParseDuration) Usage() string    { return usageDuration }
198

199
const usageEscape = `
200
A '\' inside a "-delimited string is interpreted as an escape character.
201

202
The following escape sequences are supported:
203
\b, \t, \n, \f, \r, \", \\, \uXXXX, and \UXXXXXXXX
204

205
To prevent a '\' from being recognized as an escape character, use either:
206

207
- a ' or '''-delimited string; escape characters aren't processed in them; or
208
- write two backslashes to get a single backslash: '\\'.
209

210
If you're trying to add a Windows path (e.g. "C:\Users\martin") then using '/'
211
instead of '\' will usually also work: "C:/Users/martin".
212
`
213

214
const usageInlineNewline = `
215
Inline tables must always be on a single line:
216

217
    table = {key = 42, second = 43}
218

219
It is invalid to split them over multiple lines like so:
220

221
    # INVALID
222
    table = {
223
        key    = 42,
224
        second = 43
225
    }
226

227
Use regular for this:
228

229
    [table]
230
    key    = 42
231
    second = 43
232
`
233

234
const usageStringNewline = `
235
Strings must always be on a single line, and cannot span more than one line:
236

237
    # INVALID
238
    string = "Hello,
239
    world!"
240

241
Instead use """ or ''' to split strings over multiple lines:
242

243
    string = """Hello,
244
    world!"""
245
`
246

247
const usageIntOverflow = `
248
This number is too large; this may be an error in the TOML, but it can also be a
249
bug in the program that uses too small of an integer.
250

251
The maximum and minimum values are:
252

253
    size   │ lowest         │ highest
254
    ───────┼────────────────┼──────────
255
    int8   │ -128           │ 127
256
    int16  │ -32,768        │ 32,767
257
    int32  │ -2,147,483,648 │ 2,147,483,647
258
    int64  │ -9.2 × 10¹⁷    │ 9.2 × 10¹⁷
259
    uint8  │ 0              │ 255
260
    uint16 │ 0              │ 65535
261
    uint32 │ 0              │ 4294967295
262
    uint64 │ 0              │ 1.8 × 10¹⁸
263

264
int refers to int32 on 32-bit systems and int64 on 64-bit systems.
265
`
266

267
const usageDuration = `
268
A duration must be as "number<unit>", without any spaces. Valid units are:
269

270
    ns         nanoseconds (billionth of a second)
271
    us, µs     microseconds (millionth of a second)
272
    ms         milliseconds (thousands of a second)
273
    s          seconds
274
    m          minutes
275
    h          hours
276

277
You can combine multiple units; for example "5m10s" for 5 minutes and 10
278
seconds.
279
`
280

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.