gofront 1.8.0 → 1.9.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -3
- package/package.json +6 -5
- package/src/backend/js/expressions.js +1157 -408
- package/src/backend/js/index.js +327 -153
- package/src/backend/js/natives.js +383 -0
- package/src/backend/js/runtime.js +559 -2552
- package/src/backend/js/statements.js +670 -158
- package/src/backend/js/stdlib/index.js +45 -93
- package/src/backend/js/templ.js +32 -45
- package/src/backend/js/type-info.js +298 -19
- package/src/backend/shared/fixed-float.js +20 -0
- package/src/backend/shared/fmt-types.js +91 -170
- package/src/backend/shared/host-unicode.js +36 -0
- package/src/backend/wasm/boundary.js +490 -965
- package/src/backend/wasm/emit-builtins.js +884 -256
- package/src/backend/wasm/emit-exprs.js +185 -77
- package/src/backend/wasm/emit-maps.js +17 -367
- package/src/backend/wasm/emit-shared.js +4 -1
- package/src/backend/wasm/emit-stmts.js +524 -240
- package/src/backend/wasm/emit.js +176 -38
- package/src/backend/wasm/globals.js +48 -8
- package/src/backend/wasm/glue.js +2 -4
- package/src/backend/wasm/index.js +44 -530
- package/src/backend/wasm/method-expr.js +12 -1
- package/src/backend/wasm/module-emitter.js +299 -770
- package/src/backend/wasm/monomorph.js +139 -8
- package/src/backend/wasm/natives.js +600 -0
- package/src/backend/wasm/prescan.js +5 -153
- package/src/backend/wasm/prune-funcs.js +89 -0
- package/src/backend/wasm/stdlib/index.js +2 -32
- package/src/backend/wasm/types.js +97 -20
- package/src/backend/wasm/variadic.js +9 -4
- package/src/cli/cli-core.js +5 -1
- package/src/cli/test-runner.js +115 -342
- package/src/compiler.js +113 -130
- package/src/lexer/lexer.js +106 -11
- package/src/lexer/templ-lexer.js +61 -18
- package/src/lexer/tokens.js +1 -0
- package/src/link/stdlib.js +355 -132
- package/src/link/type-names.js +204 -0
- package/src/link/wasm.js +30 -6
- package/src/lower/bounds.js +153 -0
- package/src/lower/captures.js +92 -33
- package/src/lower/embedding.js +62 -5
- package/src/lower/errors-as.js +196 -0
- package/src/lower/fmt-formatters.js +929 -0
- package/src/lower/functions.js +225 -7
- package/src/lower/gen-types.js +293 -0
- package/src/lower/index.js +14 -2
- package/src/lower/json-codecs.js +334 -245
- package/src/lower/ownership.js +25 -7
- package/src/lower/reachability.js +69 -51
- package/src/lower/walk.js +12 -0
- package/src/parser/declarations.js +30 -5
- package/src/parser/expressions.js +111 -57
- package/src/parser/statements.js +108 -0
- package/src/parser/templ.js +44 -5
- package/src/parser/types.js +12 -0
- package/src/resolver.js +1 -2
- package/src/typechecker/assignability.js +214 -19
- package/src/typechecker/const-fold.js +70 -27
- package/src/typechecker/constants.js +156 -8
- package/src/typechecker/expressions.js +490 -108
- package/src/typechecker/index.js +346 -42
- package/src/typechecker/init-order.js +136 -40
- package/src/typechecker/operand-text.js +41 -0
- package/src/typechecker/resolve.js +490 -65
- package/src/typechecker/statements.js +288 -27
- package/src/typechecker/stdlib/excluded.js +9 -5
- package/src/typechecker/stdlib/index.js +25 -9
- package/src/typechecker/termination.js +10 -1
- package/src/typechecker/types.js +287 -575
- package/stdlib/bytes/buffer.go +479 -0
- package/stdlib/bytes/bytes.go +1010 -0
- package/stdlib/bytes/reader.go +161 -0
- package/stdlib/context/context.go +115 -0
- package/stdlib/crypto/rand/rand.go +34 -0
- package/stdlib/crypto/sha256/sha256.go +249 -0
- package/stdlib/encoding/base64/base64.go +331 -0
- package/stdlib/encoding/binary/binary.go +332 -0
- package/stdlib/encoding/hex/hex.go +140 -0
- package/stdlib/encoding/json/json.go +62 -0
- package/stdlib/errors/errors.go +174 -0
- package/stdlib/fmt/errors.go +110 -0
- package/stdlib/fmt/format.go +732 -0
- package/stdlib/fmt/print.go +1232 -0
- package/stdlib/gom/gom.go +293 -0
- package/stdlib/html/html.go +251 -0
- package/stdlib/internal/fmtrt/fmtrt.go +163 -0
- package/stdlib/internal/jsonrt/dec.go +171 -38
- package/stdlib/internal/jsonrt/enc.go +186 -36
- package/stdlib/internal/jsonrt/scanner.go +17 -8
- package/stdlib/io/io.go +157 -1
- package/stdlib/maps/maps.go +131 -0
- package/stdlib/math/bits/bits.go +507 -0
- package/stdlib/math/extra.go +16 -14
- package/stdlib/math/math.go +439 -0
- package/stdlib/math/rand/rand.go +297 -0
- package/stdlib/os/os.go +93 -0
- package/stdlib/path/filepath/filepath.go +47 -0
- package/stdlib/path/path.go +394 -0
- package/stdlib/regexp/regexp.go +231 -0
- package/stdlib/slices/slices.go +526 -0
- package/stdlib/slices/sort.go +209 -0
- package/stdlib/slices/zsort_cmp.go +480 -0
- package/stdlib/slices/zsort_ordered.go +482 -0
- package/stdlib/sort/sort.go +391 -452
- package/stdlib/sort/zsort_func.go +480 -0
- package/stdlib/sort/zsort_iface.go +480 -0
- package/stdlib/strconv/float.go +1699 -0
- package/stdlib/strconv/isprint.go +752 -0
- package/stdlib/strconv/quote.go +235 -50
- package/stdlib/strconv/strconv.go +616 -0
- package/stdlib/strings/builder.go +95 -0
- package/stdlib/strings/reader.go +163 -0
- package/stdlib/strings/replacer.go +102 -0
- package/stdlib/strings/strings.go +807 -0
- package/stdlib/sync/sync.go +268 -0
- package/stdlib/testing/async_js.go +61 -0
- package/stdlib/testing/benchmark.go +297 -0
- package/stdlib/testing/testing.go +523 -0
- package/stdlib/time/duration.go +233 -0
- package/stdlib/time/format.go +745 -0
- package/stdlib/time/parse.go +790 -0
- package/stdlib/time/sleep_js.go +63 -0
- package/stdlib/time/time.go +834 -0
- package/stdlib/unicode/unicode.go +141 -3
- package/stdlib/unicode/utf8/utf8.go +464 -0
- package/src/backend/js/fmt-runtime.js +0 -573
- package/src/backend/js/stdlib/base64.js +0 -12
- package/src/backend/js/stdlib/binary.js +0 -102
- package/src/backend/js/stdlib/bits.js +0 -119
- package/src/backend/js/stdlib/builder.js +0 -98
- package/src/backend/js/stdlib/bytes.js +0 -368
- package/src/backend/js/stdlib/errors.js +0 -45
- package/src/backend/js/stdlib/fmt.js +0 -517
- package/src/backend/js/stdlib/gom.js +0 -155
- package/src/backend/js/stdlib/hex.js +0 -17
- package/src/backend/js/stdlib/html.js +0 -20
- package/src/backend/js/stdlib/io.js +0 -137
- package/src/backend/js/stdlib/json.js +0 -1167
- package/src/backend/js/stdlib/maps.js +0 -37
- package/src/backend/js/stdlib/math.js +0 -85
- package/src/backend/js/stdlib/os.js +0 -13
- package/src/backend/js/stdlib/path.js +0 -48
- package/src/backend/js/stdlib/rand.js +0 -32
- package/src/backend/js/stdlib/regexp.js +0 -54
- package/src/backend/js/stdlib/sha256.js +0 -12
- package/src/backend/js/stdlib/shared.js +0 -17
- package/src/backend/js/stdlib/simd.js +0 -34
- package/src/backend/js/stdlib/slices.js +0 -107
- package/src/backend/js/stdlib/sort.js +0 -30
- package/src/backend/js/stdlib/strconv.js +0 -79
- package/src/backend/js/stdlib/strings.js +0 -301
- package/src/backend/js/stdlib/sync.js +0 -13
- package/src/backend/js/stdlib/testing.js +0 -41
- package/src/backend/js/stdlib/time.js +0 -152
- package/src/backend/js/stdlib/unicode.js +0 -25
- package/src/backend/js/stdlib/utf8.js +0 -26
- package/src/backend/wasm/stdlib/bytes.js +0 -6716
- package/src/backend/wasm/stdlib/core.js +0 -10278
- package/src/backend/wasm/stdlib/io.js +0 -3578
- package/src/backend/wasm/stdlib/packages.js +0 -2402
- package/src/backend/wasm/stdlib/pure.js +0 -720
- package/src/backend/wasm/stdlib/time.js +0 -2229
- package/src/typechecker/stdlib/core.js +0 -1079
- package/src/typechecker/stdlib/extended.js +0 -1210
- package/stdlib/bytes/iter.go +0 -192
- package/stdlib/bytes/search.go +0 -240
- package/stdlib/bytes/split.go +0 -218
- package/stdlib/errors/overlay.go +0 -12
- package/stdlib/maps/iter.go +0 -65
- package/stdlib/slices/extra.go +0 -73
- package/stdlib/slices/iter.go +0 -113
- package/stdlib/strings/extra.go +0 -35
- package/stdlib/strings/iter.go +0 -122
- package/stdlib/sync/extra.go +0 -105
- package/stdlib/unicode/utf8/bytes.go +0 -239
|
@@ -0,0 +1,1232 @@
|
|
|
1
|
+
// Copyright 2009 The Go Authors. All rights reserved.
|
|
2
|
+
// Use of this source code is governed by a BSD-style
|
|
3
|
+
// license that can be found in the LICENSE file.
|
|
4
|
+
|
|
5
|
+
//go:build gofront
|
|
6
|
+
|
|
7
|
+
//gofront:target both
|
|
8
|
+
|
|
9
|
+
// Package fmt formats values like the real package.
|
|
10
|
+
//
|
|
11
|
+
// Where Go's fmt asks reflection for the type of an operand, this package
|
|
12
|
+
// reads a description of it (fmtrt.Arg). The compiler writes the description
|
|
13
|
+
// for operands whose type it knows at the call and for the types a package
|
|
14
|
+
// stores in interfaces; see internal/fmtrt.
|
|
15
|
+
package fmt
|
|
16
|
+
|
|
17
|
+
import (
|
|
18
|
+
"internal/fmtrt"
|
|
19
|
+
"io"
|
|
20
|
+
"os"
|
|
21
|
+
"unicode/utf8"
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
// Stringer is implemented by any value that has a String method, which
|
|
25
|
+
// defines the “native” format for that value.
|
|
26
|
+
type Stringer interface {
|
|
27
|
+
String() string
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// GoStringer is implemented by any value that has a GoString method, which
|
|
31
|
+
// defines the Go syntax for that value.
|
|
32
|
+
type GoStringer interface {
|
|
33
|
+
GoString() string
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const (
|
|
37
|
+
commaSpaceString = ", "
|
|
38
|
+
nilAngleString = "<nil>"
|
|
39
|
+
nilParenString = "(nil)"
|
|
40
|
+
nilString = "nil"
|
|
41
|
+
mapString = "map["
|
|
42
|
+
percentBangString = "%!"
|
|
43
|
+
missingString = "(MISSING)"
|
|
44
|
+
badIndexString = "(BADINDEX)"
|
|
45
|
+
panicString = "(PANIC="
|
|
46
|
+
extraString = "%!(EXTRA "
|
|
47
|
+
badWidthString = "%!(BADWIDTH)"
|
|
48
|
+
badPrecString = "%!(BADPREC)"
|
|
49
|
+
noVerbString = "%!(NOVERB)"
|
|
50
|
+
invReflectString = "<invalid reflect.Value>"
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
// pp is the printer state.
|
|
54
|
+
type pp struct {
|
|
55
|
+
fmt fmtState
|
|
56
|
+
|
|
57
|
+
// erroring is set when printing an error string to guard against calling handleMethods.
|
|
58
|
+
erroring bool
|
|
59
|
+
// panicking is set by catchPanic to avoid infinite panic, recover, panic, ... recursion.
|
|
60
|
+
panicking bool
|
|
61
|
+
// wrapErrs is set by Errorf: %w is valid only there.
|
|
62
|
+
wrapErrs bool
|
|
63
|
+
// reordered records whether the format used an explicit argument index.
|
|
64
|
+
reordered bool
|
|
65
|
+
// goodArgNum records whether the current verb's argument index was valid.
|
|
66
|
+
goodArgNum bool
|
|
67
|
+
// wrappedErrs holds the argument numbers of the %w verbs.
|
|
68
|
+
wrappedErrs []int
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
func newPrinter() *pp {
|
|
72
|
+
p := &pp{}
|
|
73
|
+
p.fmt.buf = make([]byte, 64)
|
|
74
|
+
return p
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
func (p *pp) writeString(s string) {
|
|
78
|
+
p.fmt.putString(s)
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
func (p *pp) writeByte(c byte) {
|
|
82
|
+
p.fmt.putByte(c)
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
func (p *pp) writeRune(r rune) {
|
|
86
|
+
if r >= 0 && r < 0x80 {
|
|
87
|
+
p.fmt.putByte(byte(r))
|
|
88
|
+
return
|
|
89
|
+
}
|
|
90
|
+
p.fmt.putString(string(r))
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// Fprintf formats according to a format specifier and writes to w.
|
|
94
|
+
func Fprintf(w io.Writer, format string, a ...any) (n int, err error) {
|
|
95
|
+
p := newPrinter()
|
|
96
|
+
p.doPrintf(format, a)
|
|
97
|
+
n, err = w.Write(p.fmt.bytes())
|
|
98
|
+
return
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// Printf formats according to a format specifier and writes to standard output.
|
|
102
|
+
func Printf(format string, a ...any) (n int, err error) {
|
|
103
|
+
return Fprintf(os.Stdout, format, a...)
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// Sprintf formats according to a format specifier and returns the resulting string.
|
|
107
|
+
func Sprintf(format string, a ...any) string {
|
|
108
|
+
p := newPrinter()
|
|
109
|
+
p.doPrintf(format, a)
|
|
110
|
+
return string(p.fmt.bytes())
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// Appendf formats according to a format specifier, appends the result to the
|
|
114
|
+
// byte slice, and returns the updated slice.
|
|
115
|
+
func Appendf(b []byte, format string, a ...any) []byte {
|
|
116
|
+
p := newPrinter()
|
|
117
|
+
p.doPrintf(format, a)
|
|
118
|
+
return append(b, p.fmt.bytes()...)
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// Fprint formats using the default formats for its operands and writes to w.
|
|
122
|
+
// Spaces are added between operands when neither is a string.
|
|
123
|
+
func Fprint(w io.Writer, a ...any) (n int, err error) {
|
|
124
|
+
p := newPrinter()
|
|
125
|
+
p.doPrint(a)
|
|
126
|
+
n, err = w.Write(p.fmt.bytes())
|
|
127
|
+
return
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// Print formats using the default formats for its operands and writes to standard output.
|
|
131
|
+
func Print(a ...any) (n int, err error) {
|
|
132
|
+
return Fprint(os.Stdout, a...)
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// Sprint formats using the default formats for its operands and returns the resulting string.
|
|
136
|
+
func Sprint(a ...any) string {
|
|
137
|
+
p := newPrinter()
|
|
138
|
+
p.doPrint(a)
|
|
139
|
+
return string(p.fmt.bytes())
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// Append formats using the default formats for its operands, appends the result to
|
|
143
|
+
// the byte slice, and returns the updated slice.
|
|
144
|
+
func Append(b []byte, a ...any) []byte {
|
|
145
|
+
p := newPrinter()
|
|
146
|
+
p.doPrint(a)
|
|
147
|
+
return append(b, p.fmt.bytes()...)
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// Fprintln formats using the default formats for its operands and writes to w.
|
|
151
|
+
// Spaces are always added between operands and a newline is appended.
|
|
152
|
+
func Fprintln(w io.Writer, a ...any) (n int, err error) {
|
|
153
|
+
p := newPrinter()
|
|
154
|
+
p.doPrintln(a)
|
|
155
|
+
n, err = w.Write(p.fmt.bytes())
|
|
156
|
+
return
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// Println formats using the default formats for its operands and writes to standard output.
|
|
160
|
+
func Println(a ...any) (n int, err error) {
|
|
161
|
+
return Fprintln(os.Stdout, a...)
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// Sprintln formats using the default formats for its operands and returns the resulting string.
|
|
165
|
+
func Sprintln(a ...any) string {
|
|
166
|
+
p := newPrinter()
|
|
167
|
+
p.doPrintln(a)
|
|
168
|
+
return string(p.fmt.bytes())
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// Appendln formats using the default formats for its operands, appends the result
|
|
172
|
+
// to the byte slice, and returns the updated slice.
|
|
173
|
+
func Appendln(b []byte, a ...any) []byte {
|
|
174
|
+
p := newPrinter()
|
|
175
|
+
p.doPrintln(a)
|
|
176
|
+
return append(b, p.fmt.bytes()...)
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// describe turns an operand into its description. An operand the compiler
|
|
180
|
+
// described is returned as it is; any other is described by its dynamic
|
|
181
|
+
// type, through the lookups of the packages that registered one.
|
|
182
|
+
func describe(arg any) fmtrt.Arg {
|
|
183
|
+
switch f := arg.(type) {
|
|
184
|
+
case fmtrt.Arg:
|
|
185
|
+
return f
|
|
186
|
+
case nil:
|
|
187
|
+
return fmtrt.Arg{K: fmtrt.KInterface}
|
|
188
|
+
case bool:
|
|
189
|
+
return fmtrt.Arg{K: fmtrt.KBool, T: "bool", B: f}
|
|
190
|
+
case int:
|
|
191
|
+
return fmtrt.Arg{K: fmtrt.KInt, T: "int", I: int64(f)}
|
|
192
|
+
case int8:
|
|
193
|
+
return fmtrt.Arg{K: fmtrt.KInt, T: "int8", Size: 8, I: int64(f)}
|
|
194
|
+
case int16:
|
|
195
|
+
return fmtrt.Arg{K: fmtrt.KInt, T: "int16", Size: 16, I: int64(f)}
|
|
196
|
+
case int32:
|
|
197
|
+
return fmtrt.Arg{K: fmtrt.KInt, T: "int32", Size: 32, I: int64(f)}
|
|
198
|
+
case int64:
|
|
199
|
+
return fmtrt.Arg{K: fmtrt.KInt, T: "int64", Size: 64, I: f}
|
|
200
|
+
case uint:
|
|
201
|
+
return fmtrt.Arg{K: fmtrt.KUint, T: "uint", U: uint64(f)}
|
|
202
|
+
case uint8:
|
|
203
|
+
return fmtrt.Arg{K: fmtrt.KUint, T: "uint8", Size: 8, U: uint64(f)}
|
|
204
|
+
case uint16:
|
|
205
|
+
return fmtrt.Arg{K: fmtrt.KUint, T: "uint16", Size: 16, U: uint64(f)}
|
|
206
|
+
case uint32:
|
|
207
|
+
return fmtrt.Arg{K: fmtrt.KUint, T: "uint32", Size: 32, U: uint64(f)}
|
|
208
|
+
case uint64:
|
|
209
|
+
return fmtrt.Arg{K: fmtrt.KUint, T: "uint64", Size: 64, U: f}
|
|
210
|
+
case uintptr:
|
|
211
|
+
return fmtrt.Arg{K: fmtrt.KUint, T: "uintptr", U: uint64(f)}
|
|
212
|
+
// float64 first: on JS a float32 and a float64 are the same number, and a
|
|
213
|
+
// float32 that reaches here without its description is far rarer.
|
|
214
|
+
case float64:
|
|
215
|
+
return fmtrt.Arg{K: fmtrt.KFloat, T: "float64", Size: 64, R: f}
|
|
216
|
+
case float32:
|
|
217
|
+
return fmtrt.Arg{K: fmtrt.KFloat, T: "float32", Size: 32, R: float64(f)}
|
|
218
|
+
case complex128:
|
|
219
|
+
return fmtrt.Arg{K: fmtrt.KComplex, T: "complex128", Size: 128, R: real(f), Im: imag(f)}
|
|
220
|
+
case complex64:
|
|
221
|
+
return fmtrt.Arg{K: fmtrt.KComplex, T: "complex64", Size: 64, R: float64(real(f)), Im: float64(imag(f))}
|
|
222
|
+
case string:
|
|
223
|
+
return fmtrt.Arg{K: fmtrt.KString, T: "string", S: f}
|
|
224
|
+
case []byte:
|
|
225
|
+
return bytesArg(f, "[]uint8")
|
|
226
|
+
}
|
|
227
|
+
// A value with String, GoString or Error methods is formatted through
|
|
228
|
+
// them for the verbs that call them; a verb that does not (%d) formats it
|
|
229
|
+
// by its fields, which printDesc then asks the registered lookups for.
|
|
230
|
+
e, isErr := arg.(error)
|
|
231
|
+
s, isStr := arg.(Stringer)
|
|
232
|
+
g, isGo := arg.(GoStringer)
|
|
233
|
+
if isErr || isStr || isGo {
|
|
234
|
+
a := fmtrt.Arg{K: fmtrt.KNone, V: arg}
|
|
235
|
+
if isErr {
|
|
236
|
+
a.Err = e
|
|
237
|
+
}
|
|
238
|
+
if isStr {
|
|
239
|
+
a.Str = s
|
|
240
|
+
}
|
|
241
|
+
if isGo {
|
|
242
|
+
a.GoStr = g
|
|
243
|
+
}
|
|
244
|
+
return a
|
|
245
|
+
}
|
|
246
|
+
if a, ok := fmtrt.Lookup(arg); ok {
|
|
247
|
+
return a
|
|
248
|
+
}
|
|
249
|
+
return fmtrt.Arg{K: fmtrt.KNone, V: arg}
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
// typeName is the type %T prints: the one the operand was described with, else
|
|
253
|
+
// the one a registered lookup gives its value, else the one a value of the
|
|
254
|
+
// standard library names itself.
|
|
255
|
+
func typeName(a fmtrt.Arg) string {
|
|
256
|
+
if a.T != "" || a.V == nil {
|
|
257
|
+
return a.T
|
|
258
|
+
}
|
|
259
|
+
if d, ok := fmtrt.Lookup(a.V); ok && d.T != "" {
|
|
260
|
+
return d.T
|
|
261
|
+
}
|
|
262
|
+
if n, ok := a.V.(interface{ GofrontTypeName() string }); ok {
|
|
263
|
+
return n.GofrontTypeName()
|
|
264
|
+
}
|
|
265
|
+
return ""
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
// bytesArg describes a []byte.
|
|
269
|
+
func bytesArg(b []byte, typ string) fmtrt.Arg {
|
|
270
|
+
return fmtrt.Arg{
|
|
271
|
+
K: fmtrt.KSlice, T: typ, Nil: b == nil, Ptr: b, N: len(b), IsBytes: true, Bytes: b,
|
|
272
|
+
Elem: func(i int) fmtrt.Arg {
|
|
273
|
+
return fmtrt.Arg{K: fmtrt.KUint, T: "uint8", Size: 8, U: uint64(b[i])}
|
|
274
|
+
},
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
func (p *pp) doPrint(a []any) {
|
|
279
|
+
prevString := false
|
|
280
|
+
for argNum, arg := range a {
|
|
281
|
+
d := describe(arg)
|
|
282
|
+
isString := d.K == fmtrt.KString
|
|
283
|
+
// Add a space between two non-string arguments.
|
|
284
|
+
if argNum > 0 && !isString && !prevString {
|
|
285
|
+
p.writeByte(' ')
|
|
286
|
+
}
|
|
287
|
+
p.printArg(d, 'v')
|
|
288
|
+
prevString = isString
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
// doPrintln is like doPrint but always adds a space between arguments
|
|
293
|
+
// and a newline after the last argument.
|
|
294
|
+
func (p *pp) doPrintln(a []any) {
|
|
295
|
+
for argNum, arg := range a {
|
|
296
|
+
if argNum > 0 {
|
|
297
|
+
p.writeByte(' ')
|
|
298
|
+
}
|
|
299
|
+
p.printArg(describe(arg), 'v')
|
|
300
|
+
}
|
|
301
|
+
p.writeByte('\n')
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
func (p *pp) badVerb(verb rune, a fmtrt.Arg) {
|
|
305
|
+
p.erroring = true
|
|
306
|
+
p.writeString(percentBangString)
|
|
307
|
+
p.writeRune(verb)
|
|
308
|
+
p.writeByte('(')
|
|
309
|
+
if a.K == fmtrt.KInterface && a.V == nil {
|
|
310
|
+
p.writeString(nilAngleString)
|
|
311
|
+
} else {
|
|
312
|
+
p.writeString(typeName(a))
|
|
313
|
+
p.writeByte('=')
|
|
314
|
+
p.printDesc(a, 'v', 0, false)
|
|
315
|
+
}
|
|
316
|
+
p.writeByte(')')
|
|
317
|
+
p.erroring = false
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
func (p *pp) fmtBool(v bool, verb rune, a fmtrt.Arg) {
|
|
321
|
+
switch verb {
|
|
322
|
+
case 't', 'v':
|
|
323
|
+
p.fmt.fmtBoolean(v)
|
|
324
|
+
default:
|
|
325
|
+
p.badVerb(verb, a)
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
// fmt0x64 formats a uint64 in hexadecimal and prefixes it with 0x or
|
|
330
|
+
// not, as requested, by temporarily setting the sharp flag.
|
|
331
|
+
func (p *pp) fmt0x64(v uint64, leading0x bool) {
|
|
332
|
+
sharp := p.fmt.sharp
|
|
333
|
+
p.fmt.sharp = leading0x
|
|
334
|
+
p.fmt.fmtInteger(v, 16, unsigned, 'v', ldigits)
|
|
335
|
+
p.fmt.sharp = sharp
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
// fmtInteger formats a signed or unsigned integer.
|
|
339
|
+
func (p *pp) fmtInteger(v uint64, isSigned bool, verb rune, a fmtrt.Arg) {
|
|
340
|
+
switch verb {
|
|
341
|
+
case 'v':
|
|
342
|
+
if p.fmt.sharpV && !isSigned {
|
|
343
|
+
p.fmt0x64(v, true)
|
|
344
|
+
} else {
|
|
345
|
+
p.fmt.fmtInteger(v, 10, isSigned, verb, ldigits)
|
|
346
|
+
}
|
|
347
|
+
case 'd':
|
|
348
|
+
p.fmt.fmtInteger(v, 10, isSigned, verb, ldigits)
|
|
349
|
+
case 'b':
|
|
350
|
+
p.fmt.fmtInteger(v, 2, isSigned, verb, ldigits)
|
|
351
|
+
case 'o', 'O':
|
|
352
|
+
p.fmt.fmtInteger(v, 8, isSigned, verb, ldigits)
|
|
353
|
+
case 'x':
|
|
354
|
+
p.fmt.fmtInteger(v, 16, isSigned, verb, ldigits)
|
|
355
|
+
case 'X':
|
|
356
|
+
p.fmt.fmtInteger(v, 16, isSigned, verb, udigits)
|
|
357
|
+
case 'c':
|
|
358
|
+
p.fmt.fmtC(v)
|
|
359
|
+
case 'q':
|
|
360
|
+
p.fmt.fmtQc(v)
|
|
361
|
+
case 'U':
|
|
362
|
+
p.fmt.fmtUnicode(v)
|
|
363
|
+
default:
|
|
364
|
+
p.badVerb(verb, a)
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
// fmtFloat formats a float. The format is the verb's default; the size is 32 or 64.
|
|
369
|
+
func (p *pp) fmtFloat(v float64, size int, verb rune, a fmtrt.Arg) {
|
|
370
|
+
switch verb {
|
|
371
|
+
case 'v':
|
|
372
|
+
p.fmt.fmtFloat(v, size, 'g', -1)
|
|
373
|
+
case 'b', 'g', 'G', 'x', 'X':
|
|
374
|
+
p.fmt.fmtFloat(v, size, verb, -1)
|
|
375
|
+
case 'f', 'e', 'E':
|
|
376
|
+
p.fmt.fmtFloat(v, size, verb, 6)
|
|
377
|
+
case 'F':
|
|
378
|
+
p.fmt.fmtFloat(v, size, 'f', 6)
|
|
379
|
+
default:
|
|
380
|
+
p.badVerb(verb, a)
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
// fmtComplex formats a complex number v with
|
|
385
|
+
// r = real(v) and j = imag(v) as (r+ji) using
|
|
386
|
+
// fmtFloat for r and j formatting.
|
|
387
|
+
func (p *pp) fmtComplex(re, im float64, size int, verb rune, a fmtrt.Arg) {
|
|
388
|
+
// Make sure any unsupported verbs are found before the
|
|
389
|
+
// calls to fmtFloat to not generate an incorrect error string.
|
|
390
|
+
switch verb {
|
|
391
|
+
case 'v', 'b', 'g', 'G', 'x', 'X', 'f', 'F', 'e', 'E':
|
|
392
|
+
oldPlus := p.fmt.plus
|
|
393
|
+
p.writeByte('(')
|
|
394
|
+
p.fmtFloat(re, size/2, verb, a)
|
|
395
|
+
// Imaginary part always has a sign.
|
|
396
|
+
p.fmt.plus = true
|
|
397
|
+
p.fmtFloat(im, size/2, verb, a)
|
|
398
|
+
p.writeString("i)")
|
|
399
|
+
p.fmt.plus = oldPlus
|
|
400
|
+
default:
|
|
401
|
+
p.badVerb(verb, a)
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
func (p *pp) fmtString(v string, verb rune, a fmtrt.Arg) {
|
|
406
|
+
switch verb {
|
|
407
|
+
case 'v':
|
|
408
|
+
if p.fmt.sharpV {
|
|
409
|
+
p.fmt.fmtQ(v)
|
|
410
|
+
} else {
|
|
411
|
+
p.fmt.fmtS(v)
|
|
412
|
+
}
|
|
413
|
+
case 's':
|
|
414
|
+
p.fmt.fmtS(v)
|
|
415
|
+
case 'x':
|
|
416
|
+
p.fmt.fmtSx(v, ldigits)
|
|
417
|
+
case 'X':
|
|
418
|
+
p.fmt.fmtSx(v, udigits)
|
|
419
|
+
case 'q':
|
|
420
|
+
p.fmt.fmtQ(v)
|
|
421
|
+
default:
|
|
422
|
+
p.badVerb(verb, a)
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
func (p *pp) fmtBytes(v []byte, verb rune, a fmtrt.Arg) {
|
|
427
|
+
switch verb {
|
|
428
|
+
case 'v', 'd':
|
|
429
|
+
if p.fmt.sharpV {
|
|
430
|
+
p.writeString(a.T)
|
|
431
|
+
if v == nil {
|
|
432
|
+
p.writeString(nilParenString)
|
|
433
|
+
return
|
|
434
|
+
}
|
|
435
|
+
p.writeByte('{')
|
|
436
|
+
for i, c := range v {
|
|
437
|
+
if i > 0 {
|
|
438
|
+
p.writeString(commaSpaceString)
|
|
439
|
+
}
|
|
440
|
+
p.fmt0x64(uint64(c), true)
|
|
441
|
+
}
|
|
442
|
+
p.writeByte('}')
|
|
443
|
+
} else {
|
|
444
|
+
p.writeByte('[')
|
|
445
|
+
for i, c := range v {
|
|
446
|
+
if i > 0 {
|
|
447
|
+
p.writeByte(' ')
|
|
448
|
+
}
|
|
449
|
+
p.fmt.fmtInteger(uint64(c), 10, unsigned, verb, ldigits)
|
|
450
|
+
}
|
|
451
|
+
p.writeByte(']')
|
|
452
|
+
}
|
|
453
|
+
case 's':
|
|
454
|
+
p.fmt.fmtBs(v)
|
|
455
|
+
case 'x':
|
|
456
|
+
p.fmt.fmtBx(v, ldigits)
|
|
457
|
+
case 'X':
|
|
458
|
+
p.fmt.fmtBx(v, udigits)
|
|
459
|
+
case 'q':
|
|
460
|
+
p.fmt.fmtQ(string(v))
|
|
461
|
+
default:
|
|
462
|
+
p.printElems(a, verb, 0, false)
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
func (p *pp) fmtPointer(a fmtrt.Arg, verb rune) {
|
|
467
|
+
var u uint64
|
|
468
|
+
switch a.K {
|
|
469
|
+
case fmtrt.KChan, fmtrt.KFunc, fmtrt.KPtr, fmtrt.KUnsafePtr, fmtrt.KMap, fmtrt.KSlice:
|
|
470
|
+
if !a.Nil {
|
|
471
|
+
u = fmtrt.ArgPtrID(a)
|
|
472
|
+
}
|
|
473
|
+
default:
|
|
474
|
+
p.badVerb(verb, a)
|
|
475
|
+
return
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
switch verb {
|
|
479
|
+
case 'v':
|
|
480
|
+
if p.fmt.sharpV {
|
|
481
|
+
p.writeByte('(')
|
|
482
|
+
p.writeString(a.T)
|
|
483
|
+
p.writeString(")(")
|
|
484
|
+
if u == 0 {
|
|
485
|
+
p.writeString(nilString)
|
|
486
|
+
} else {
|
|
487
|
+
p.fmt0x64(u, true)
|
|
488
|
+
}
|
|
489
|
+
p.writeByte(')')
|
|
490
|
+
} else {
|
|
491
|
+
if u == 0 {
|
|
492
|
+
p.fmt.padString(nilAngleString)
|
|
493
|
+
} else {
|
|
494
|
+
p.fmt0x64(u, !p.fmt.sharp)
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
case 'p':
|
|
498
|
+
p.fmt0x64(u, !p.fmt.sharp)
|
|
499
|
+
case 'b', 'o', 'd', 'x', 'X':
|
|
500
|
+
p.fmtInteger(u, unsigned, verb, a)
|
|
501
|
+
default:
|
|
502
|
+
p.badVerb(verb, a)
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
// callMethod runs f, one of the String, GoString or Error methods of the
|
|
507
|
+
// operand, and writes the string it returns. A panic in the method is
|
|
508
|
+
// reported in the output; a nil receiver prints as <nil>.
|
|
509
|
+
func (p *pp) callMethod(a fmtrt.Arg, verb rune, method string, f func() string) {
|
|
510
|
+
defer func() {
|
|
511
|
+
if err := recover(); err != nil {
|
|
512
|
+
// If it's a nil pointer, just say "<nil>". The likeliest causes are a
|
|
513
|
+
// Stringer that fails to guard against nil or a nil pointer for a
|
|
514
|
+
// value receiver, and in either case, "<nil>" is a nice result.
|
|
515
|
+
if a.K == fmtrt.KPtr && a.Nil {
|
|
516
|
+
p.writeString(nilAngleString)
|
|
517
|
+
return
|
|
518
|
+
}
|
|
519
|
+
// Otherwise print a concise panic message. Most of the time the panic
|
|
520
|
+
// value will print itself nicely.
|
|
521
|
+
if p.panicking {
|
|
522
|
+
// Nested panics; the recursion in printArg cannot succeed.
|
|
523
|
+
panic(err)
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
oldFlags := p.fmt.saveFlags()
|
|
527
|
+
// For this output we want default behavior.
|
|
528
|
+
p.fmt.clearflags()
|
|
529
|
+
|
|
530
|
+
p.writeString(percentBangString)
|
|
531
|
+
p.writeRune(verb)
|
|
532
|
+
p.writeString(panicString)
|
|
533
|
+
p.writeString(method)
|
|
534
|
+
p.writeString(" method: ")
|
|
535
|
+
p.panicking = true
|
|
536
|
+
p.printArg(describe(err), 'v')
|
|
537
|
+
p.panicking = false
|
|
538
|
+
p.writeByte(')')
|
|
539
|
+
|
|
540
|
+
p.fmt.restoreFlags(oldFlags)
|
|
541
|
+
}
|
|
542
|
+
}()
|
|
543
|
+
if method == "GoString" {
|
|
544
|
+
p.fmt.fmtS(f())
|
|
545
|
+
return
|
|
546
|
+
}
|
|
547
|
+
p.fmtString(f(), verb, a)
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
// handleMethods calls the String, GoString or Error method of the operand.
|
|
551
|
+
// A value reached through an unexported field (ro) answers only to Error:
|
|
552
|
+
// reflection cannot call its other methods.
|
|
553
|
+
func (p *pp) handleMethods(a fmtrt.Arg, verb rune, ro bool) (handled bool) {
|
|
554
|
+
if p.erroring {
|
|
555
|
+
return
|
|
556
|
+
}
|
|
557
|
+
if verb == 'w' {
|
|
558
|
+
// It is invalid to use %w other than with Errorf or with a non-error arg.
|
|
559
|
+
if a.Err == nil || !p.wrapErrs {
|
|
560
|
+
p.badVerb(verb, a)
|
|
561
|
+
return true
|
|
562
|
+
}
|
|
563
|
+
// Format the error as %v.
|
|
564
|
+
verb = 'v'
|
|
565
|
+
}
|
|
566
|
+
// If we're doing Go syntax and the argument knows how to supply it, take care of it now.
|
|
567
|
+
if p.fmt.sharpV {
|
|
568
|
+
if a.GoStr != nil && !ro {
|
|
569
|
+
handled = true
|
|
570
|
+
p.callMethod(a, verb, "GoString", func() string { return a.GoStr.GoString() })
|
|
571
|
+
return
|
|
572
|
+
}
|
|
573
|
+
} else {
|
|
574
|
+
// If a string is acceptable according to the format, see if
|
|
575
|
+
// the value satisfies one of the string-valued interfaces.
|
|
576
|
+
// Println etc. set verb to %v, which is "stringable".
|
|
577
|
+
switch verb {
|
|
578
|
+
case 'v', 's', 'x', 'X', 'q':
|
|
579
|
+
// Is it an error or Stringer?
|
|
580
|
+
// The duplication in the bodies is necessary:
|
|
581
|
+
// setting handled and deferring catchPanic
|
|
582
|
+
// must happen before calling the method.
|
|
583
|
+
if a.Err != nil {
|
|
584
|
+
handled = true
|
|
585
|
+
p.callMethod(a, verb, "Error", func() string { return a.Err.Error() })
|
|
586
|
+
return
|
|
587
|
+
}
|
|
588
|
+
if a.Str != nil && !ro {
|
|
589
|
+
handled = true
|
|
590
|
+
p.callMethod(a, verb, "String", func() string { return a.Str.String() })
|
|
591
|
+
return
|
|
592
|
+
}
|
|
593
|
+
}
|
|
594
|
+
}
|
|
595
|
+
return false
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
func (p *pp) printArg(a fmtrt.Arg, verb rune) {
|
|
599
|
+
if a.K == fmtrt.KInterface && a.V == nil && a.T == "" {
|
|
600
|
+
switch verb {
|
|
601
|
+
case 'T', 'v':
|
|
602
|
+
p.fmt.padString(nilAngleString)
|
|
603
|
+
default:
|
|
604
|
+
p.badVerb(verb, a)
|
|
605
|
+
}
|
|
606
|
+
return
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
// Special processing considerations.
|
|
610
|
+
// %T (the value's type) and %p (its address) are special; we always do them first.
|
|
611
|
+
switch verb {
|
|
612
|
+
case 'T':
|
|
613
|
+
p.fmt.fmtS(typeName(a))
|
|
614
|
+
return
|
|
615
|
+
case 'p':
|
|
616
|
+
p.fmtPointer(a, 'p')
|
|
617
|
+
return
|
|
618
|
+
}
|
|
619
|
+
p.printDesc(a, verb, 0, false)
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
// printDesc formats one described value. depth is how deeply it is nested in
|
|
623
|
+
// the operand: a pointer prints as the value it points to only at depth 0.
|
|
624
|
+
func (p *pp) printDesc(a fmtrt.Arg, verb rune, depth int, ro bool) {
|
|
625
|
+
if a.K == fmtrt.KInterface {
|
|
626
|
+
if a.V == nil {
|
|
627
|
+
p.writeString(nilAngleString)
|
|
628
|
+
return
|
|
629
|
+
}
|
|
630
|
+
// An operand held in an interface at the top level is the operand
|
|
631
|
+
// itself: Go's printArg reflects on its dynamic value.
|
|
632
|
+
if depth > 0 {
|
|
633
|
+
depth++
|
|
634
|
+
}
|
|
635
|
+
p.printDesc(describe(a.V), verb, depth, ro)
|
|
636
|
+
return
|
|
637
|
+
}
|
|
638
|
+
if p.handleMethods(a, verb, ro) {
|
|
639
|
+
return
|
|
640
|
+
}
|
|
641
|
+
switch a.K {
|
|
642
|
+
case fmtrt.KBool:
|
|
643
|
+
p.fmtBool(a.B, verb, a)
|
|
644
|
+
case fmtrt.KInt:
|
|
645
|
+
p.fmtInteger(uint64(a.I), signed, verb, a)
|
|
646
|
+
case fmtrt.KUint:
|
|
647
|
+
p.fmtInteger(a.U, unsigned, verb, a)
|
|
648
|
+
case fmtrt.KFloat:
|
|
649
|
+
p.fmtFloat(a.R, a.Size, verb, a)
|
|
650
|
+
case fmtrt.KComplex:
|
|
651
|
+
p.fmtComplex(a.R, a.Im, a.Size, verb, a)
|
|
652
|
+
case fmtrt.KString:
|
|
653
|
+
p.fmtString(a.S, verb, a)
|
|
654
|
+
case fmtrt.KMap:
|
|
655
|
+
p.printMap(a, verb, depth, ro)
|
|
656
|
+
case fmtrt.KStruct:
|
|
657
|
+
p.printStruct(a, verb, depth, ro)
|
|
658
|
+
case fmtrt.KArray, fmtrt.KSlice:
|
|
659
|
+
if a.IsBytes {
|
|
660
|
+
switch verb {
|
|
661
|
+
case 's', 'q', 'x', 'X', 'v', 'd':
|
|
662
|
+
p.fmtBytes(a.Bytes, verb, a)
|
|
663
|
+
return
|
|
664
|
+
}
|
|
665
|
+
}
|
|
666
|
+
p.printElems(a, verb, depth, ro)
|
|
667
|
+
case fmtrt.KPtr:
|
|
668
|
+
// pointer to array or slice or struct? ok at top level
|
|
669
|
+
// but not embedded (avoid loops)
|
|
670
|
+
if depth == 0 && !a.Nil && a.Inner != nil {
|
|
671
|
+
p.writeByte('&')
|
|
672
|
+
p.printDesc(a.Inner(), verb, depth+1, ro)
|
|
673
|
+
return
|
|
674
|
+
}
|
|
675
|
+
p.fmtPointer(a, verb)
|
|
676
|
+
case fmtrt.KChan, fmtrt.KFunc, fmtrt.KUnsafePtr:
|
|
677
|
+
p.fmtPointer(a, verb)
|
|
678
|
+
default:
|
|
679
|
+
// A value whose methods did not apply: describe it by its fields.
|
|
680
|
+
if a.K == fmtrt.KNone && a.V != nil && (a.Err != nil || a.Str != nil || a.GoStr != nil) {
|
|
681
|
+
if d, ok := fmtrt.Lookup(a.V); ok {
|
|
682
|
+
d.Err, d.Str, d.GoStr = a.Err, a.Str, a.GoStr
|
|
683
|
+
p.printDesc(d, verb, depth, ro)
|
|
684
|
+
return
|
|
685
|
+
}
|
|
686
|
+
}
|
|
687
|
+
// The error errors.New returns is a pointer to a struct of a package
|
|
688
|
+
// that fmt cannot spell: it prints itself.
|
|
689
|
+
if f, ok := a.V.(interface{ GofrontFmt(rune) string }); ok && depth == 0 {
|
|
690
|
+
p.writeString(f.GofrontFmt(verb))
|
|
691
|
+
return
|
|
692
|
+
}
|
|
693
|
+
// A value of a type no generated description covers. What reaches
|
|
694
|
+
// here is a nil func in an interface, which has no type to look up,
|
|
695
|
+
// and prints as nil.
|
|
696
|
+
if a.V == nil || verb == 'v' {
|
|
697
|
+
p.writeString(nilAngleString)
|
|
698
|
+
return
|
|
699
|
+
}
|
|
700
|
+
p.writeString(percentBangString)
|
|
701
|
+
p.writeRune(verb)
|
|
702
|
+
p.writeString("(unknown)")
|
|
703
|
+
}
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
// isExported reports whether a field name is exported.
|
|
707
|
+
func isExported(name string) bool {
|
|
708
|
+
return name != "" && name[0] >= 'A' && name[0] <= 'Z'
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
func (p *pp) printStruct(a fmtrt.Arg, verb rune, depth int, ro bool) {
|
|
712
|
+
if p.fmt.sharpV {
|
|
713
|
+
p.writeString(a.T)
|
|
714
|
+
}
|
|
715
|
+
p.writeByte('{')
|
|
716
|
+
for i := 0; i < a.N; i++ {
|
|
717
|
+
if i > 0 {
|
|
718
|
+
if p.fmt.sharpV {
|
|
719
|
+
p.writeString(commaSpaceString)
|
|
720
|
+
} else {
|
|
721
|
+
p.writeByte(' ')
|
|
722
|
+
}
|
|
723
|
+
}
|
|
724
|
+
name, f := a.Field(i)
|
|
725
|
+
if p.fmt.plusV || p.fmt.sharpV {
|
|
726
|
+
if name != "" {
|
|
727
|
+
p.writeString(name)
|
|
728
|
+
p.writeByte(':')
|
|
729
|
+
}
|
|
730
|
+
}
|
|
731
|
+
p.printDesc(f, verb, depth+1, ro || !isExported(name))
|
|
732
|
+
}
|
|
733
|
+
p.writeByte('}')
|
|
734
|
+
}
|
|
735
|
+
|
|
736
|
+
func (p *pp) printElems(a fmtrt.Arg, verb rune, depth int, ro bool) {
|
|
737
|
+
if p.fmt.sharpV {
|
|
738
|
+
p.writeString(a.T)
|
|
739
|
+
if a.K == fmtrt.KSlice && a.Nil {
|
|
740
|
+
p.writeString(nilParenString)
|
|
741
|
+
return
|
|
742
|
+
}
|
|
743
|
+
p.writeByte('{')
|
|
744
|
+
for i := 0; i < a.N; i++ {
|
|
745
|
+
if i > 0 {
|
|
746
|
+
p.writeString(commaSpaceString)
|
|
747
|
+
}
|
|
748
|
+
p.printDesc(a.Elem(i), verb, depth+1, ro)
|
|
749
|
+
}
|
|
750
|
+
p.writeByte('}')
|
|
751
|
+
return
|
|
752
|
+
}
|
|
753
|
+
p.writeByte('[')
|
|
754
|
+
for i := 0; i < a.N; i++ {
|
|
755
|
+
if i > 0 {
|
|
756
|
+
p.writeByte(' ')
|
|
757
|
+
}
|
|
758
|
+
p.printDesc(a.Elem(i), verb, depth+1, ro)
|
|
759
|
+
}
|
|
760
|
+
p.writeByte(']')
|
|
761
|
+
}
|
|
762
|
+
|
|
763
|
+
func (p *pp) printMap(a fmtrt.Arg, verb rune, depth int, ro bool) {
|
|
764
|
+
if p.fmt.sharpV {
|
|
765
|
+
p.writeString(a.T)
|
|
766
|
+
if a.Nil {
|
|
767
|
+
p.writeString(nilParenString)
|
|
768
|
+
return
|
|
769
|
+
}
|
|
770
|
+
p.writeByte('{')
|
|
771
|
+
} else {
|
|
772
|
+
p.writeString(mapString)
|
|
773
|
+
}
|
|
774
|
+
entries := sortedEntries(a.Entries())
|
|
775
|
+
for i, e := range entries {
|
|
776
|
+
if i > 0 {
|
|
777
|
+
if p.fmt.sharpV {
|
|
778
|
+
p.writeString(commaSpaceString)
|
|
779
|
+
} else {
|
|
780
|
+
p.writeByte(' ')
|
|
781
|
+
}
|
|
782
|
+
}
|
|
783
|
+
p.printDesc(e.Key, verb, depth+1, ro)
|
|
784
|
+
p.writeByte(':')
|
|
785
|
+
p.printDesc(e.Val, verb, depth+1, ro)
|
|
786
|
+
}
|
|
787
|
+
if p.fmt.sharpV {
|
|
788
|
+
p.writeByte('}')
|
|
789
|
+
} else {
|
|
790
|
+
p.writeByte(']')
|
|
791
|
+
}
|
|
792
|
+
}
|
|
793
|
+
|
|
794
|
+
// sortedEntries orders map entries like internal/fmtsort: by key, with
|
|
795
|
+
// structs and arrays compared field by field.
|
|
796
|
+
func sortedEntries(es []fmtrt.Entry) []fmtrt.Entry {
|
|
797
|
+
if len(es) < 2 {
|
|
798
|
+
return es
|
|
799
|
+
}
|
|
800
|
+
return mergeEntries(es, make([]fmtrt.Entry, len(es)))
|
|
801
|
+
}
|
|
802
|
+
|
|
803
|
+
// mergeEntries is a stable merge sort of es using tmp as scratch space. It
|
|
804
|
+
// keeps fmt from importing slices, whose source every fmt user would
|
|
805
|
+
// otherwise have to parse and check.
|
|
806
|
+
func mergeEntries(es, tmp []fmtrt.Entry) []fmtrt.Entry {
|
|
807
|
+
if len(es) < 2 {
|
|
808
|
+
return es
|
|
809
|
+
}
|
|
810
|
+
mid := len(es) / 2
|
|
811
|
+
left := mergeEntries(es[:mid], tmp[:mid])
|
|
812
|
+
right := mergeEntries(es[mid:], tmp[mid:])
|
|
813
|
+
i, j, k := 0, 0, 0
|
|
814
|
+
for i < len(left) && j < len(right) {
|
|
815
|
+
if compareArgs(right[j].Key, left[i].Key) < 0 {
|
|
816
|
+
tmp[k] = right[j]
|
|
817
|
+
j++
|
|
818
|
+
} else {
|
|
819
|
+
tmp[k] = left[i]
|
|
820
|
+
i++
|
|
821
|
+
}
|
|
822
|
+
k++
|
|
823
|
+
}
|
|
824
|
+
for i < len(left) {
|
|
825
|
+
tmp[k] = left[i]
|
|
826
|
+
i++
|
|
827
|
+
k++
|
|
828
|
+
}
|
|
829
|
+
for j < len(right) {
|
|
830
|
+
tmp[k] = right[j]
|
|
831
|
+
j++
|
|
832
|
+
k++
|
|
833
|
+
}
|
|
834
|
+
copy(es, tmp[:k])
|
|
835
|
+
return es
|
|
836
|
+
}
|
|
837
|
+
|
|
838
|
+
func compareInt(a, b int64) int {
|
|
839
|
+
if a < b {
|
|
840
|
+
return -1
|
|
841
|
+
}
|
|
842
|
+
if a > b {
|
|
843
|
+
return 1
|
|
844
|
+
}
|
|
845
|
+
return 0
|
|
846
|
+
}
|
|
847
|
+
|
|
848
|
+
func compareUint(a, b uint64) int {
|
|
849
|
+
if a < b {
|
|
850
|
+
return -1
|
|
851
|
+
}
|
|
852
|
+
if a > b {
|
|
853
|
+
return 1
|
|
854
|
+
}
|
|
855
|
+
return 0
|
|
856
|
+
}
|
|
857
|
+
|
|
858
|
+
func compareFloat(a, b float64) int {
|
|
859
|
+
switch {
|
|
860
|
+
case a < b:
|
|
861
|
+
return -1
|
|
862
|
+
case a > b:
|
|
863
|
+
return 1
|
|
864
|
+
case a == b:
|
|
865
|
+
return 0
|
|
866
|
+
}
|
|
867
|
+
// NaN compares less than non-NaN floats.
|
|
868
|
+
switch {
|
|
869
|
+
case a != a && b != b:
|
|
870
|
+
return 0
|
|
871
|
+
case a != a:
|
|
872
|
+
return -1
|
|
873
|
+
}
|
|
874
|
+
return 1
|
|
875
|
+
}
|
|
876
|
+
|
|
877
|
+
// compareArgs is the order fmt prints map keys in.
|
|
878
|
+
func compareArgs(a, b fmtrt.Arg) int {
|
|
879
|
+
if a.K == fmtrt.KInterface || b.K == fmtrt.KInterface {
|
|
880
|
+
// nil sorts before everything else.
|
|
881
|
+
if a.V == nil || b.V == nil {
|
|
882
|
+
return compareInt(boolInt(a.V != nil), boolInt(b.V != nil))
|
|
883
|
+
}
|
|
884
|
+
x, y := describe(a.V), describe(b.V)
|
|
885
|
+
if x.T != y.T {
|
|
886
|
+
// Values of different types: the order of Go's type descriptors,
|
|
887
|
+
// which this mirrors for the common cases, a named type before its
|
|
888
|
+
// underlying type and strings before numbers.
|
|
889
|
+
if x.K != y.K {
|
|
890
|
+
return compareInt(int64(y.K), int64(x.K))
|
|
891
|
+
}
|
|
892
|
+
if x.T < y.T {
|
|
893
|
+
return -1
|
|
894
|
+
}
|
|
895
|
+
return 1
|
|
896
|
+
}
|
|
897
|
+
return compareArgs(x, y)
|
|
898
|
+
}
|
|
899
|
+
if a.K != b.K {
|
|
900
|
+
return compareInt(int64(a.K), int64(b.K))
|
|
901
|
+
}
|
|
902
|
+
switch a.K {
|
|
903
|
+
case fmtrt.KBool:
|
|
904
|
+
return compareInt(boolInt(a.B), boolInt(b.B))
|
|
905
|
+
case fmtrt.KInt:
|
|
906
|
+
return compareInt(a.I, b.I)
|
|
907
|
+
case fmtrt.KUint:
|
|
908
|
+
return compareUint(a.U, b.U)
|
|
909
|
+
case fmtrt.KFloat:
|
|
910
|
+
return compareFloat(a.R, b.R)
|
|
911
|
+
case fmtrt.KComplex:
|
|
912
|
+
if c := compareFloat(a.R, b.R); c != 0 {
|
|
913
|
+
return c
|
|
914
|
+
}
|
|
915
|
+
return compareFloat(a.Im, b.Im)
|
|
916
|
+
case fmtrt.KString:
|
|
917
|
+
if a.S < b.S {
|
|
918
|
+
return -1
|
|
919
|
+
}
|
|
920
|
+
if a.S > b.S {
|
|
921
|
+
return 1
|
|
922
|
+
}
|
|
923
|
+
return 0
|
|
924
|
+
case fmtrt.KPtr, fmtrt.KChan, fmtrt.KUnsafePtr:
|
|
925
|
+
return compareUint(fmtrt.ArgPtrID(a), fmtrt.ArgPtrID(b))
|
|
926
|
+
case fmtrt.KStruct:
|
|
927
|
+
for i := 0; i < a.N; i++ {
|
|
928
|
+
_, x := a.Field(i)
|
|
929
|
+
_, y := b.Field(i)
|
|
930
|
+
if c := compareArgs(x, y); c != 0 {
|
|
931
|
+
return c
|
|
932
|
+
}
|
|
933
|
+
}
|
|
934
|
+
case fmtrt.KArray:
|
|
935
|
+
for i := 0; i < a.N; i++ {
|
|
936
|
+
if c := compareArgs(a.Elem(i), b.Elem(i)); c != 0 {
|
|
937
|
+
return c
|
|
938
|
+
}
|
|
939
|
+
}
|
|
940
|
+
}
|
|
941
|
+
return 0
|
|
942
|
+
}
|
|
943
|
+
|
|
944
|
+
func boolInt(b bool) int64 {
|
|
945
|
+
if b {
|
|
946
|
+
return 1
|
|
947
|
+
}
|
|
948
|
+
return 0
|
|
949
|
+
}
|
|
950
|
+
|
|
951
|
+
// tooLarge reports whether the magnitude of the integer is
|
|
952
|
+
// too large to be used as a formatting width or precision.
|
|
953
|
+
func tooLarge(x int) bool {
|
|
954
|
+
const max int = 1e6
|
|
955
|
+
return x > max || x < -max
|
|
956
|
+
}
|
|
957
|
+
|
|
958
|
+
// parsenum converts ASCII to integer. num is 0 (and isnum is false) if no number present.
|
|
959
|
+
func parsenum(s string, start, end int) (num int, isnum bool, newi int) {
|
|
960
|
+
if start >= end {
|
|
961
|
+
return 0, false, end
|
|
962
|
+
}
|
|
963
|
+
for newi = start; newi < end && '0' <= s[newi] && s[newi] <= '9'; newi++ {
|
|
964
|
+
if tooLarge(num) {
|
|
965
|
+
return 0, false, end // Overflow; crazy long number most likely.
|
|
966
|
+
}
|
|
967
|
+
num = num*10 + int(s[newi]-'0')
|
|
968
|
+
isnum = true
|
|
969
|
+
}
|
|
970
|
+
return
|
|
971
|
+
}
|
|
972
|
+
|
|
973
|
+
// intFromArg reads the integer operand of a * width or precision.
|
|
974
|
+
func intFromArg(a []any, argNum int) (num int, isInt bool, newArgNum int) {
|
|
975
|
+
newArgNum = argNum
|
|
976
|
+
if argNum < len(a) {
|
|
977
|
+
d := describe(a[argNum])
|
|
978
|
+
switch d.K {
|
|
979
|
+
case fmtrt.KInt:
|
|
980
|
+
if int64(int(d.I)) == d.I {
|
|
981
|
+
num = int(d.I)
|
|
982
|
+
isInt = true
|
|
983
|
+
}
|
|
984
|
+
case fmtrt.KUint:
|
|
985
|
+
if int64(d.U) >= 0 && uint64(int(d.U)) == d.U {
|
|
986
|
+
num = int(d.U)
|
|
987
|
+
isInt = true
|
|
988
|
+
}
|
|
989
|
+
}
|
|
990
|
+
newArgNum = argNum + 1
|
|
991
|
+
if tooLarge(num) {
|
|
992
|
+
num = 0
|
|
993
|
+
isInt = false
|
|
994
|
+
}
|
|
995
|
+
}
|
|
996
|
+
return
|
|
997
|
+
}
|
|
998
|
+
|
|
999
|
+
// parseArgNumber returns the value of the bracketed number, minus 1
|
|
1000
|
+
// (explicit argument numbers are one-indexed but we want zero-indexed).
|
|
1001
|
+
// The opening bracket is known to be present at format[0].
|
|
1002
|
+
// The returned values are the index, the number of bytes to consume
|
|
1003
|
+
// up to the closing paren, if present, and whether the number parsed
|
|
1004
|
+
// ok. The bytes to consume will be 1 if no closing paren is present.
|
|
1005
|
+
func parseArgNumber(format string) (index int, wid int, ok bool) {
|
|
1006
|
+
// There must be at least 3 bytes: [n].
|
|
1007
|
+
if len(format) < 3 {
|
|
1008
|
+
return 0, 1, false
|
|
1009
|
+
}
|
|
1010
|
+
|
|
1011
|
+
// Find closing bracket.
|
|
1012
|
+
for i := 1; i < len(format); i++ {
|
|
1013
|
+
if format[i] == ']' {
|
|
1014
|
+
width, ok, newi := parsenum(format, 1, i)
|
|
1015
|
+
if !ok || newi != i {
|
|
1016
|
+
return 0, i + 1, false
|
|
1017
|
+
}
|
|
1018
|
+
return width - 1, i + 1, true // arg numbers are one-indexed and skip paren.
|
|
1019
|
+
}
|
|
1020
|
+
}
|
|
1021
|
+
return 0, 1, false
|
|
1022
|
+
}
|
|
1023
|
+
|
|
1024
|
+
// argNumber returns the next argument to evaluate, which is either the value of the passed-in
|
|
1025
|
+
// argNum or the value of the bracketed integer that begins format[i:]. It also returns
|
|
1026
|
+
// the new value of i, that is, the index of the next byte of the format to process.
|
|
1027
|
+
func (p *pp) argNumber(argNum int, format string, i int, numArgs int) (newArgNum, newi int, found bool) {
|
|
1028
|
+
if len(format) <= i || format[i] != '[' {
|
|
1029
|
+
return argNum, i, false
|
|
1030
|
+
}
|
|
1031
|
+
p.reordered = true
|
|
1032
|
+
index, wid, ok := parseArgNumber(format[i:])
|
|
1033
|
+
if ok && 0 <= index && index < numArgs {
|
|
1034
|
+
return index, i + wid, true
|
|
1035
|
+
}
|
|
1036
|
+
p.goodArgNum = false
|
|
1037
|
+
return argNum, i + wid, ok
|
|
1038
|
+
}
|
|
1039
|
+
|
|
1040
|
+
func (p *pp) badArgNum(verb rune) {
|
|
1041
|
+
p.writeString(percentBangString)
|
|
1042
|
+
p.writeRune(verb)
|
|
1043
|
+
p.writeString(badIndexString)
|
|
1044
|
+
}
|
|
1045
|
+
|
|
1046
|
+
func (p *pp) missingArg(verb rune) {
|
|
1047
|
+
p.writeString(percentBangString)
|
|
1048
|
+
p.writeRune(verb)
|
|
1049
|
+
p.writeString(missingString)
|
|
1050
|
+
}
|
|
1051
|
+
|
|
1052
|
+
func (p *pp) doPrintf(format string, a []any) {
|
|
1053
|
+
end := len(format)
|
|
1054
|
+
argNum := 0 // we process one argument per non-trivial format
|
|
1055
|
+
afterIndex := false // previous item in format was an index like [3].
|
|
1056
|
+
p.reordered = false
|
|
1057
|
+
formatLoop:
|
|
1058
|
+
for i := 0; i < end; {
|
|
1059
|
+
p.goodArgNum = true
|
|
1060
|
+
lasti := i
|
|
1061
|
+
for i < end && format[i] != '%' {
|
|
1062
|
+
i++
|
|
1063
|
+
}
|
|
1064
|
+
if i > lasti {
|
|
1065
|
+
p.writeString(format[lasti:i])
|
|
1066
|
+
}
|
|
1067
|
+
if i >= end {
|
|
1068
|
+
// done processing format string
|
|
1069
|
+
break
|
|
1070
|
+
}
|
|
1071
|
+
|
|
1072
|
+
// Process one verb
|
|
1073
|
+
i++
|
|
1074
|
+
|
|
1075
|
+
// Do we have flags?
|
|
1076
|
+
p.fmt.clearflags()
|
|
1077
|
+
simpleFormat:
|
|
1078
|
+
for ; i < end; i++ {
|
|
1079
|
+
c := format[i]
|
|
1080
|
+
switch c {
|
|
1081
|
+
case '#':
|
|
1082
|
+
p.fmt.sharp = true
|
|
1083
|
+
case '0':
|
|
1084
|
+
p.fmt.zero = true
|
|
1085
|
+
case '+':
|
|
1086
|
+
p.fmt.plus = true
|
|
1087
|
+
case '-':
|
|
1088
|
+
p.fmt.minus = true
|
|
1089
|
+
case ' ':
|
|
1090
|
+
p.fmt.space = true
|
|
1091
|
+
default:
|
|
1092
|
+
// Fast path for common case of ascii lower case simple verbs
|
|
1093
|
+
// without precision or width or argument indices.
|
|
1094
|
+
if 'a' <= c && c <= 'z' && argNum < len(a) {
|
|
1095
|
+
switch c {
|
|
1096
|
+
case 'w':
|
|
1097
|
+
p.wrappedErrs = append(p.wrappedErrs, argNum)
|
|
1098
|
+
fallthrough
|
|
1099
|
+
case 'v':
|
|
1100
|
+
// Go syntax
|
|
1101
|
+
p.fmt.sharpV = p.fmt.sharp
|
|
1102
|
+
p.fmt.sharp = false
|
|
1103
|
+
// Struct-field syntax
|
|
1104
|
+
p.fmt.plusV = p.fmt.plus
|
|
1105
|
+
p.fmt.plus = false
|
|
1106
|
+
}
|
|
1107
|
+
p.printArg(describe(a[argNum]), rune(c))
|
|
1108
|
+
argNum++
|
|
1109
|
+
i++
|
|
1110
|
+
continue formatLoop
|
|
1111
|
+
}
|
|
1112
|
+
// Format is more complex than simple flags and a verb or is malformed.
|
|
1113
|
+
break simpleFormat
|
|
1114
|
+
}
|
|
1115
|
+
}
|
|
1116
|
+
|
|
1117
|
+
// Do we have an explicit argument index?
|
|
1118
|
+
argNum, i, afterIndex = p.argNumber(argNum, format, i, len(a))
|
|
1119
|
+
|
|
1120
|
+
// Do we have width?
|
|
1121
|
+
if i < end && format[i] == '*' {
|
|
1122
|
+
i++
|
|
1123
|
+
p.fmt.wid, p.fmt.widPresent, argNum = intFromArg(a, argNum)
|
|
1124
|
+
|
|
1125
|
+
if !p.fmt.widPresent {
|
|
1126
|
+
p.writeString(badWidthString)
|
|
1127
|
+
}
|
|
1128
|
+
|
|
1129
|
+
// We have a negative width, so take its value and ensure
|
|
1130
|
+
// that the minus flag is set
|
|
1131
|
+
if p.fmt.wid < 0 {
|
|
1132
|
+
p.fmt.wid = -p.fmt.wid
|
|
1133
|
+
p.fmt.minus = true
|
|
1134
|
+
p.fmt.zero = false // Do not pad with zeros to the right.
|
|
1135
|
+
}
|
|
1136
|
+
afterIndex = false
|
|
1137
|
+
} else {
|
|
1138
|
+
p.fmt.wid, p.fmt.widPresent, i = parsenum(format, i, end)
|
|
1139
|
+
if afterIndex && p.fmt.widPresent { // "%[3]2d"
|
|
1140
|
+
p.goodArgNum = false
|
|
1141
|
+
}
|
|
1142
|
+
}
|
|
1143
|
+
|
|
1144
|
+
// Do we have precision?
|
|
1145
|
+
if i+1 <= end && format[i] == '.' {
|
|
1146
|
+
i++
|
|
1147
|
+
if afterIndex { // "%[3].2d"
|
|
1148
|
+
p.goodArgNum = false
|
|
1149
|
+
}
|
|
1150
|
+
argNum, i, afterIndex = p.argNumber(argNum, format, i, len(a))
|
|
1151
|
+
if i < end && format[i] == '*' {
|
|
1152
|
+
i++
|
|
1153
|
+
p.fmt.prec, p.fmt.precPresent, argNum = intFromArg(a, argNum)
|
|
1154
|
+
// Negative precision arguments don't make sense
|
|
1155
|
+
if p.fmt.prec < 0 {
|
|
1156
|
+
p.fmt.prec = 0
|
|
1157
|
+
p.fmt.precPresent = false
|
|
1158
|
+
}
|
|
1159
|
+
if !p.fmt.precPresent {
|
|
1160
|
+
p.writeString(badPrecString)
|
|
1161
|
+
}
|
|
1162
|
+
afterIndex = false
|
|
1163
|
+
} else {
|
|
1164
|
+
p.fmt.prec, p.fmt.precPresent, i = parsenum(format, i, end)
|
|
1165
|
+
if !p.fmt.precPresent {
|
|
1166
|
+
p.fmt.prec = 0
|
|
1167
|
+
p.fmt.precPresent = true
|
|
1168
|
+
}
|
|
1169
|
+
}
|
|
1170
|
+
}
|
|
1171
|
+
|
|
1172
|
+
if !afterIndex {
|
|
1173
|
+
argNum, i, afterIndex = p.argNumber(argNum, format, i, len(a))
|
|
1174
|
+
}
|
|
1175
|
+
|
|
1176
|
+
if i >= end {
|
|
1177
|
+
p.writeString(noVerbString)
|
|
1178
|
+
break
|
|
1179
|
+
}
|
|
1180
|
+
|
|
1181
|
+
verb, size := rune(format[i]), 1
|
|
1182
|
+
if verb >= utf8.RuneSelf {
|
|
1183
|
+
verb, size = utf8.DecodeRuneInString(format[i:])
|
|
1184
|
+
}
|
|
1185
|
+
i += size
|
|
1186
|
+
|
|
1187
|
+
switch {
|
|
1188
|
+
case verb == '%': // Percent does not absorb operands and ignores f.wid and f.prec.
|
|
1189
|
+
p.writeByte('%')
|
|
1190
|
+
case !p.goodArgNum:
|
|
1191
|
+
p.badArgNum(verb)
|
|
1192
|
+
case argNum >= len(a): // No argument left over to print for the current verb.
|
|
1193
|
+
p.missingArg(verb)
|
|
1194
|
+
case verb == 'w':
|
|
1195
|
+
p.wrappedErrs = append(p.wrappedErrs, argNum)
|
|
1196
|
+
fallthrough
|
|
1197
|
+
case verb == 'v':
|
|
1198
|
+
// Go syntax
|
|
1199
|
+
p.fmt.sharpV = p.fmt.sharp
|
|
1200
|
+
p.fmt.sharp = false
|
|
1201
|
+
// Struct-field syntax
|
|
1202
|
+
p.fmt.plusV = p.fmt.plus
|
|
1203
|
+
p.fmt.plus = false
|
|
1204
|
+
fallthrough
|
|
1205
|
+
default:
|
|
1206
|
+
p.printArg(describe(a[argNum]), verb)
|
|
1207
|
+
argNum++
|
|
1208
|
+
}
|
|
1209
|
+
}
|
|
1210
|
+
|
|
1211
|
+
// Check for extra arguments unless the call accessed the arguments
|
|
1212
|
+
// out of order, in which case it's too expensive to detect if they've all
|
|
1213
|
+
// been used and arguably OK if they're not.
|
|
1214
|
+
if !p.reordered && argNum < len(a) {
|
|
1215
|
+
p.fmt.clearflags()
|
|
1216
|
+
p.writeString(extraString)
|
|
1217
|
+
for i, arg := range a[argNum:] {
|
|
1218
|
+
if i > 0 {
|
|
1219
|
+
p.writeString(commaSpaceString)
|
|
1220
|
+
}
|
|
1221
|
+
if arg == nil {
|
|
1222
|
+
p.writeString(nilAngleString)
|
|
1223
|
+
} else {
|
|
1224
|
+
d := describe(arg)
|
|
1225
|
+
p.writeString(d.T)
|
|
1226
|
+
p.writeByte('=')
|
|
1227
|
+
p.printArg(d, 'v')
|
|
1228
|
+
}
|
|
1229
|
+
}
|
|
1230
|
+
p.writeByte(')')
|
|
1231
|
+
}
|
|
1232
|
+
}
|