PathrockNetwork Gno Explorer
HomeBlocksTransactionsTokensRealmsPackagesValidatorsAnalytics

PathrockNetwork Gno Explorer — an independent explorer for Gno.land Mainnet (gnoland-1), operated by PathrockNetwork. Not an official Gno.land service.

gnowebarchive RPC

gno.land/p/moul/vendor/nt/ufmt/v2

Package
Open in gnoweb ↗

Overview

Kind
Pure package
Name
v2
Namespace
moul / vendor / nt / ufmt
Files
8 (README)(gnomod.toml)
Exported functions
n/a — not supported for pure packages by the node (vm/qfuncs)
Module
gno.land/p/moul/vendor/nt/ufmt/v2
gno
0.9

Files (8)

  • README.mdmarkdown
  • gnomod.tomltoml
  • doc.gnogno
  • format.gnogno
  • print.gnogno
  • ufmt.gnogno
  • gofmt_test.gnogno
  • methods_test.gnogno
  • print.gnogno
    1package ufmt23import (4	"sort"5	"unicode/utf8"6)78

    Functions

    not supported for pure packages by the node (vm/qfuncs)

    Signatures reconstructed verbatim from vm/qfuncs — interface params keep their inline definitions.

    // This file is the high level: parsing the format, and choosing how each
    9// operand prints. It is a port of print.go in Go's fmt, minus reflect.
    10
    11const (
    12 commaSpace = ", "
    13 nilAngle = "<nil>"
    14 nilParen = "(nil)"
    15 unhandled = "(unhandled)"
    16 percentBang = "%!"
    17 missing = "(MISSING)"
    18 badIndex = "(BADINDEX)"
    19 extra = "%!(EXTRA "
    20 badWidth = "%!(BADWIDTH)"
    21 badPrec = "%!(BADPREC)"
    22 noVerb = "%!(NOVERB)"
    23)
    24
    25// printer holds the output and the state of the verb being printed.
    26type printer struct {
    27 buf []byte
    28
    29 // The flags, width and precision of the current verb.
    30 plus, minus, sharp, space, zero bool
    31 plusV, sharpV bool // %+v and %#v
    32 wid, prec int
    33 widPresent, precPresent bool
    34
    35 arg any // the operand being printed, for error messages
    36 erroring bool // printing an error message: do not call methods
    37 reordered bool // an explicit index was used
    38 goodArgNum bool // the last index was valid
    39 wrapErrs bool // Errorf: %w is allowed
    40 wrapped []int
    41}
    42
    43func newPrinter() *printer {
    44 return &printer{}
    45}
    46
    47// Write implements State, so a Formatter can write.
    48func (p *printer) Write(b []byte) (int, error) {
    49 p.buf = append(p.buf, b...)
    50 return len(b), nil
    51}
    52
    53// WriteString lets a Formatter write a string without a conversion.
    54func (p *printer) WriteString(s string) (int, error) {
    55 p.buf = append(p.buf, s...)
    56 return len(s), nil
    57}
    58
    59// Width implements State.
    60func (p *printer) Width() (int, bool) { return p.wid, p.widPresent }
    61
    62// Precision implements State.
    63func (p *printer) Precision() (int, bool) { return p.prec, p.precPresent }
    64
    65// Flag implements State.
    66func (p *printer) Flag(c int) bool {
    67 switch c {
    68 case '-':
    69 return p.minus
    70 case '+':
    71 return p.plus || p.plusV
    72 case '#':
    73 return p.sharp || p.sharpV
    74 case ' ':
    75 return p.space
    76 case '0':
    77 return p.zero
    78 }
    79 return false
    80}
    81
    82func (p *printer) writeString(s string) { p.buf = append(p.buf, s...) }
    83func (p *printer) writeByte(c byte) { p.buf = append(p.buf, c) }
    84func (p *printer) writeRune(r rune) { p.buf = utf8.AppendRune(p.buf, r) }
    85
    86// doPrint is Sprint: %v, with a space between two operands neither of which is
    87// a string.
    88func (p *printer) doPrint(a []any) {
    89 prevString := false
    90 for argNum, arg := range a {
    91 _, isString := arg.(string)
    92 if argNum > 0 && !isString && !prevString {
    93 p.writeByte(' ')
    94 }
    95 p.printArg(arg, 'v')
    96 prevString = isString
    97 }
    98}
    99
    100// doPrintln is Sprintln: %v, always a space between operands, then a newline.
    101func (p *printer) doPrintln(a []any) {
    102 for argNum, arg := range a {
    103 if argNum > 0 {
    104 p.writeByte(' ')
    105 }
    106 p.printArg(arg, 'v')
    107 }
    108 p.writeByte('\n')
    109}
    110
    111// parsenum reads a decimal number at s[start:end].
    112func parsenum(s string, start, end int) (num int, isnum bool, newi int) {
    113 if start >= end {
    114 return 0, false, end
    115 }
    116 for newi = start; newi < end && '0' <= s[newi] && s[newi] <= '9'; newi++ {
    117 if num > 1e6 {
    118 return 0, false, end // absurdly large: refuse rather than allocate
    119 }
    120 num = num*10 + int(s[newi]-'0')
    121 isnum = true
    122 }
    123 return
    124}
    125
    126// intFromArg reads a * width or precision from a[argNum].
    127func intFromArg(a []any, argNum int) (num int, isInt bool, newArgNum int) {
    128 newArgNum = argNum
    129 if argNum >= len(a) {
    130 return
    131 }
    132 isInt = true
    133 switch v := a[argNum].(type) {
    134 case int:
    135 num = v
    136 case int8:
    137 num = int(v)
    138 case int16:
    139 num = int(v)
    140 case int32:
    141 num = int(v)
    142 case int64:
    143 num = int(v)
    144 case uint:
    145 num = int(v)
    146 case uint8:
    147 num = int(v)
    148 case uint16:
    149 num = int(v)
    150 case uint32:
    151 num = int(v)
    152 case uint64:
    153 num = int(v)
    154 default:
    155 isInt = false
    156 }
    157 newArgNum = argNum + 1
    158 if num > 1e6 || num < -1e6 {
    159 num = 0
    160 isInt = false
    161 }
    162 return
    163}
    164
    165// argNumber reads an explicit index, "[3]", at format[i:].
    166func (p *printer) argNumber(argNum int, format string, i int, numArgs int) (newArgNum, newi int, found bool) {
    167 if len(format) <= i || format[i] != '[' {
    168 return argNum, i, false
    169 }
    170 p.reordered = true
    171 for j := 1; j < len(format)-i; j++ {
    172 if format[i+j] == ']' {
    173 width, ok, newi := parsenum(format, i+1, i+j)
    174 if !ok || newi != i+j {
    175 p.goodArgNum = false
    176 return argNum, i + j + 1, true
    177 }
    178 index := width - 1
    179 if index >= 0 && index < numArgs {
    180 return index, i + j + 1, true
    181 }
    182 p.goodArgNum = false
    183 return argNum, i + j + 1, true
    184 }
    185 }
    186 p.goodArgNum = false
    187 return argNum, i + 1, false
    188}
    189
    190// doPrintf is Sprintf.
    191func (p *printer) doPrintf(format string, a []any) {
    192 end := len(format)
    193 argNum := 0
    194 afterIndex := false // the previous item was an index like [3]
    195 p.reordered = false
    196
    197 for i := 0; i < end; {
    198 p.goodArgNum = true
    199 lasti := i
    200 for i < end && format[i] != '%' {
    201 i++
    202 }
    203 if i > lasti {
    204 p.writeString(format[lasti:i])
    205 }
    206 if i >= end {
    207 break
    208 }
    209 i++ // skip '%'
    210
    211 p.clearFlags()
    212
    213 // Fast path: a bare lowercase verb, "%d" or "%s", is most of what any
    214 // realm prints, and skips the specifier parsing entirely.
    215 if i < end && 'a' <= format[i] && format[i] <= 'z' && argNum < len(a) {
    216 verb := rune(format[i])
    217 if verb == 'w' {
    218 p.wrapped = append(p.wrapped, argNum)
    219 }
    220 p.printArg(a[argNum], verb)
    221 argNum++
    222 i++
    223 continue
    224 }
    225
    226 flags:
    227 for ; i < end; i++ {
    228 switch format[i] {
    229 case '#':
    230 p.sharp = true
    231 case '0':
    232 p.zero = !p.minus // zero padding only ever goes on the left
    233 case '+':
    234 p.plus = true
    235 case '-':
    236 p.minus = true
    237 p.zero = false
    238 case ' ':
    239 p.space = true
    240 default:
    241 break flags
    242 }
    243 }
    244
    245 argNum, i, afterIndex = p.argNumber(argNum, format, i, len(a))
    246
    247 // Width.
    248 if i < end && format[i] == '*' {
    249 i++
    250 p.wid, p.widPresent, argNum = intFromArg(a, argNum)
    251 if !p.widPresent {
    252 p.writeString(badWidth)
    253 }
    254 if p.wid < 0 {
    255 p.wid = -p.wid
    256 p.minus = true
    257 p.zero = false
    258 }
    259 afterIndex = false
    260 } else {
    261 p.wid, p.widPresent, i = parsenum(format, i, end)
    262 if afterIndex && p.widPresent { // "%[3]2d"
    263 p.goodArgNum = false
    264 }
    265 }
    266
    267 // Precision.
    268 if i+1 < end && format[i] == '.' {
    269 i++
    270 if afterIndex { // "%[3].2d"
    271 p.goodArgNum = false
    272 }
    273 argNum, i, afterIndex = p.argNumber(argNum, format, i, len(a))
    274 if i < end && format[i] == '*' {
    275 i++
    276 p.prec, p.precPresent, argNum = intFromArg(a, argNum)
    277 if p.prec < 0 {
    278 p.prec = 0
    279 p.precPresent = false
    280 }
    281 if !p.precPresent {
    282 p.writeString(badPrec)
    283 }
    284 afterIndex = false
    285 } else {
    286 p.prec, p.precPresent, i = parsenum(format, i, end)
    287 if !p.precPresent {
    288 p.prec = 0
    289 p.precPresent = true
    290 }
    291 }
    292 }
    293
    294 if !afterIndex {
    295 argNum, i, afterIndex = p.argNumber(argNum, format, i, len(a))
    296 }
    297
    298 if i >= end {
    299 p.writeString(noVerb)
    300 break
    301 }
    302
    303 verb, size := rune(format[i]), 1
    304 if verb >= utf8.RuneSelf {
    305 verb, size = utf8.DecodeRuneInString(format[i:])
    306 }
    307 i += size
    308
    309 switch {
    310 case verb == '%': // takes no operand, ignores width and precision
    311 p.writeByte('%')
    312 case !p.goodArgNum:
    313 p.badArgNum(verb)
    314 case argNum >= len(a):
    315 p.missingArg(verb)
    316 default:
    317 if verb == 'w' {
    318 p.wrapped = append(p.wrapped, argNum)
    319 }
    320 if verb == 'v' || verb == 'w' {
    321 p.sharpV, p.sharp = p.sharp, false
    322 p.plusV, p.plus = p.plus, false
    323 }
    324 p.printArg(a[argNum], verb)
    325 argNum++
    326 }
    327 }
    328
    329 // Report unused operands, unless an index made the count meaningless.
    330 if !p.reordered && argNum < len(a) {
    331 p.clearFlags()
    332 p.writeString(extra)
    333 for i, arg := range a[argNum:] {
    334 if i > 0 {
    335 p.writeString(commaSpace)
    336 }
    337 if arg == nil {
    338 p.writeString(nilAngle)
    339 continue
    340 }
    341 p.writeString(typeName(arg))
    342 p.writeByte('=')
    343 p.printArg(arg, 'v')
    344 }
    345 p.writeByte(')')
    346 }
    347}
    348
    349func (p *printer) badArgNum(verb rune) {
    350 p.writeString(percentBang)
    351 p.writeRune(verb)
    352 p.writeString(badIndex)
    353}
    354
    355func (p *printer) missingArg(verb rune) {
    356 p.writeString(percentBang)
    357 p.writeRune(verb)
    358 p.writeString(missing)
    359}
    360
    361// badVerb writes "%!d(string=hi)": the verb, the operand's type and its value.
    362func (p *printer) badVerb(verb rune) {
    363 p.erroring = true
    364 p.writeString(percentBang)
    365 p.writeRune(verb)
    366 p.writeByte('(')
    367 switch {
    368 case p.arg == nil:
    369 p.writeString(nilAngle)
    370 default:
    371 if t := typeName(p.arg); t != "unknown" {
    372 p.writeString(t)
    373 p.writeByte('=')
    374 p.printArg(p.arg, 'v')
    375 } else {
    376 p.writeString("unhandled")
    377 }
    378 }
    379 p.writeByte(')')
    380 p.erroring = false
    381}
    382
    383// printArg prints one operand.
    384func (p *printer) printArg(arg any, verb rune) {
    385 p.arg = arg
    386
    387 if arg == nil {
    388 switch verb {
    389 case 'T', 'v':
    390 p.padString(nilAngle)
    391 default:
    392 p.badVerb(verb)
    393 }
    394 return
    395 }
    396
    397 switch verb {
    398 case 'T':
    399 p.fmtS(typeName(arg))
    400 return
    401 case 'p':
    402 p.badVerb(verb)
    403 return
    404 }
    405
    406 // The basic types first, exactly as Go: a named type never matches these,
    407 // so its methods are still found below.
    408 switch f := arg.(type) {
    409 case bool:
    410 p.fmtBool(f, verb)
    411 case float32:
    412 p.fmtFloatVerb(float64(f), 32, verb)
    413 case float64:
    414 p.fmtFloatVerb(f, 64, verb)
    415 case int:
    416 p.fmtSigned(int64(f), verb)
    417 case int8:
    418 p.fmtSigned(int64(f), verb)
    419 case int16:
    420 p.fmtSigned(int64(f), verb)
    421 case int32:
    422 p.fmtSigned(int64(f), verb)
    423 case int64:
    424 p.fmtSigned(f, verb)
    425 case uint:
    426 p.fmtUnsigned(uint64(f), verb)
    427 case uint8:
    428 p.fmtUnsigned(uint64(f), verb)
    429 case uint16:
    430 p.fmtUnsigned(uint64(f), verb)
    431 case uint32:
    432 p.fmtUnsigned(uint64(f), verb)
    433 case uint64:
    434 p.fmtUnsigned(f, verb)
    435 case string:
    436 p.fmtString(f, verb)
    437 case []byte:
    438 p.fmtBytes(f, verb)
    439 default:
    440 if !p.handleMethods(verb) {
    441 p.printComposite(arg, verb)
    442 }
    443 }
    444}
    445
    446// handleMethods prints arg with its own Format, GoString, Error or String
    447// method, in Go's order, and reports whether it did.
    448func (p *printer) handleMethods(verb rune) (handled bool) {
    449 if p.erroring {
    450 return false
    451 }
    452 if verb == 'w' {
    453 // %w is for Errorf, and for an error.
    454 if _, ok := p.arg.(error); !ok || !p.wrapErrs {
    455 p.badVerb(verb)
    456 return true
    457 }
    458 verb = 'v'
    459 }
    460
    461 if f, ok := p.arg.(Formatter); ok {
    462 handled = true // stays true if the method panics
    463 defer p.catchPanic(p.arg, verb, "Format")
    464 f.Format(p, verb)
    465 return
    466 }
    467
    468 if p.sharpV {
    469 if g, ok := p.arg.(GoStringer); ok {
    470 handled = true
    471 defer p.catchPanic(p.arg, verb, "GoString")
    472 p.fmtS(g.GoString())
    473 return
    474 }
    475 return false
    476 }
    477
    478 switch verb {
    479 case 'v', 's', 'x', 'X', 'q':
    480 switch v := p.arg.(type) {
    481 case error:
    482 handled = true
    483 defer p.catchPanic(p.arg, verb, "Error")
    484 p.fmtString(v.Error(), verb)
    485 return
    486 case Stringer:
    487 handled = true
    488 defer p.catchPanic(p.arg, verb, "String")
    489 p.fmtString(v.String(), verb)
    490 return
    491 }
    492 }
    493 return false
    494}
    495
    496// catchPanic turns a panicking method into "%!v(PANIC=String method: msg)".
    497func (p *printer) catchPanic(arg any, verb rune, method string) {
    498 r := recover()
    499 if r == nil {
    500 return
    501 }
    502 if p.erroring {
    503 panic(r) // the method panicked again while printing its own panic
    504 }
    505 p.clearFlags()
    506 p.writeString(percentBang)
    507 p.writeRune(verb)
    508 p.writeString("(PANIC=")
    509 p.writeString(method)
    510 p.writeString(" method: ")
    511 p.erroring = true
    512 p.printArg(r, 'v')
    513 p.erroring = false
    514 p.writeByte(')')
    515}
    516
    517func (p *printer) fmtBool(v bool, verb rune) {
    518 switch verb {
    519 case 't', 'v':
    520 p.fmtBoolean(v)
    521 default:
    522 p.badVerb(verb)
    523 }
    524}
    525
    526// fmtSigned prints a signed integer. The magnitude of math.MinInt64 does not
    527// fit an int64, so it is computed without ever negating v itself.
    528func (p *printer) fmtSigned(v int64, verb rune) {
    529 if v >= 0 {
    530 p.fmtIntegerVerb(uint64(v), false, true, verb)
    531 return
    532 }
    533 mag := uint64(-(v + 1)) + 1
    534 p.fmtIntegerVerb(mag, true, true, verb)
    535}
    536
    537func (p *printer) fmtUnsigned(u uint64, verb rune) {
    538 p.fmtIntegerVerb(u, false, false, verb)
    539}
    540
    541func (p *printer) fmtIntegerVerb(u uint64, negative, isSigned bool, verb rune) {
    542 switch verb {
    543 case 'v':
    544 if p.sharpV && !isSigned {
    545 p.fmt0x64(u, true)
    546 } else {
    547 p.fmtInteger(u, negative, 10, verb, ldigits)
    548 }
    549 case 'd':
    550 p.fmtInteger(u, negative, 10, verb, ldigits)
    551 case 'b':
    552 p.fmtInteger(u, negative, 2, verb, ldigits)
    553 case 'o', 'O':
    554 p.fmtInteger(u, negative, 8, verb, ldigits)
    555 case 'x':
    556 p.fmtInteger(u, negative, 16, verb, ldigits)
    557 case 'X':
    558 p.fmtInteger(u, negative, 16, verb, udigits)
    559 case 'c', 'q', 'U':
    560 if negative {
    561 u = ^u + 1 // back to two's complement, as Go sees it: never a rune
    562 }
    563 switch verb {
    564 case 'c':
    565 p.fmtC(u)
    566 case 'q':
    567 p.fmtQc(u)
    568 default:
    569 p.fmtUnicode(u)
    570 }
    571 default:
    572 p.badVerb(verb)
    573 }
    574}
    575
    576// fmt0x64 prints u in hex with a 0x prefix (leading0x) or without one.
    577func (p *printer) fmt0x64(u uint64, leading0x bool) {
    578 sharp := p.sharp
    579 p.sharp = leading0x
    580 p.fmtInteger(u, false, 16, 'v', ldigits)
    581 p.sharp = sharp
    582}
    583
    584func (p *printer) fmtFloatVerb(v float64, size int, verb rune) {
    585 switch verb {
    586 case 'v':
    587 p.fmtFloat(v, size, 'g', -1)
    588 case 'b', 'g', 'G', 'x', 'X':
    589 p.fmtFloat(v, size, verb, -1)
    590 case 'f', 'e', 'E':
    591 p.fmtFloat(v, size, verb, 6)
    592 case 'F':
    593 p.fmtFloat(v, size, 'f', 6)
    594 default:
    595 p.badVerb(verb)
    596 }
    597}
    598
    599func (p *printer) fmtString(v string, verb rune) {
    600 switch verb {
    601 case 'v':
    602 if p.sharpV {
    603 p.fmtQ(v)
    604 } else {
    605 p.fmtS(v)
    606 }
    607 case 's':
    608 p.fmtS(v)
    609 case 'x':
    610 p.fmtSx(v, ldigits)
    611 case 'X':
    612 p.fmtSx(v, udigits)
    613 case 'q':
    614 p.fmtQ(v)
    615 default:
    616 p.badVerb(verb)
    617 }
    618}
    619
    620func (p *printer) fmtBytes(v []byte, verb rune) {
    621 switch verb {
    622 case 'v', 'd':
    623 if p.sharpV {
    624 p.writeString("[]byte")
    625 if v == nil {
    626 p.writeString(nilParen)
    627 return
    628 }
    629 p.writeByte('{')
    630 for i, c := range v {
    631 if i > 0 {
    632 p.writeString(commaSpace)
    633 }
    634 p.fmt0x64(uint64(c), true)
    635 }
    636 p.writeByte('}')
    637 return
    638 }
    639 p.writeByte('[')
    640 for i, c := range v {
    641 if i > 0 {
    642 p.writeByte(' ')
    643 }
    644 p.fmtInteger(uint64(c), false, 10, verb, ldigits)
    645 }
    646 p.writeByte(']')
    647 case 's':
    648 p.fmtS(string(v))
    649 case 'x':
    650 p.fmtSx(string(v), ldigits)
    651 case 'X':
    652 p.fmtSx(string(v), udigits)
    653 case 'q':
    654 p.fmtQ(string(v))
    655 default:
    656 // Every other verb applies to each byte, as for any slice.
    657 p.writeByte('[')
    658 for i, c := range v {
    659 if i > 0 {
    660 p.writeByte(' ')
    661 }
    662 p.fmtUnsigned(uint64(c), verb)
    663 }
    664 p.writeByte(']')
    665 }
    666}
    667
    668// printComposite prints the slices and maps gno can see without reflect.
    669func (p *printer) printComposite(arg any, verb rune) {
    670 switch v := arg.(type) {
    671 case []any:
    672 p.printSlice("[]interface {}", v == nil, len(v), func(i int) any { return v[i] }, verb)
    673 case []string:
    674 p.printSlice("[]string", v == nil, len(v), func(i int) any { return v[i] }, verb)
    675 case []error:
    676 p.printSlice("[]error", v == nil, len(v), func(i int) any { return v[i] }, verb)
    677 case []bool:
    678 p.printSlice("[]bool", v == nil, len(v), func(i int) any { return v[i] }, verb)
    679 case []int:
    680 p.printSlice("[]int", v == nil, len(v), func(i int) any { return v[i] }, verb)
    681 case []int8:
    682 p.printSlice("[]int8", v == nil, len(v), func(i int) any { return v[i] }, verb)
    683 case []int16:
    684 p.printSlice("[]int16", v == nil, len(v), func(i int) any { return v[i] }, verb)
    685 case []int32:
    686 p.printSlice("[]int32", v == nil, len(v), func(i int) any { return v[i] }, verb)
    687 case []int64:
    688 p.printSlice("[]int64", v == nil, len(v), func(i int) any { return v[i] }, verb)
    689 case []uint:
    690 p.printSlice("[]uint", v == nil, len(v), func(i int) any { return v[i] }, verb)
    691 case []uint16:
    692 p.printSlice("[]uint16", v == nil, len(v), func(i int) any { return v[i] }, verb)
    693 case []uint32:
    694 p.printSlice("[]uint32", v == nil, len(v), func(i int) any { return v[i] }, verb)
    695 case []uint64:
    696 p.printSlice("[]uint64", v == nil, len(v), func(i int) any { return v[i] }, verb)
    697 case []float32:
    698 p.printSlice("[]float32", v == nil, len(v), func(i int) any { return v[i] }, verb)
    699 case []float64:
    700 p.printSlice("[]float64", v == nil, len(v), func(i int) any { return v[i] }, verb)
    701 case map[string]string:
    702 keys := sortedKeys(len(v), func(add func(string)) {
    703 for k := range v {
    704 add(k)
    705 }
    706 })
    707 p.printMap("map[string]string", v == nil, keys, func(k string) any { return v[k] }, verb)
    708 case map[string]any:
    709 keys := sortedKeys(len(v), func(add func(string)) {
    710 for k := range v {
    711 add(k)
    712 }
    713 })
    714 p.printMap("map[string]interface {}", v == nil, keys, func(k string) any { return v[k] }, verb)
    715 case map[string]int:
    716 keys := sortedKeys(len(v), func(add func(string)) {
    717 for k := range v {
    718 add(k)
    719 }
    720 })
    721 p.printMap("map[string]int", v == nil, keys, func(k string) any { return v[k] }, verb)
    722 case map[string]bool:
    723 keys := sortedKeys(len(v), func(add func(string)) {
    724 for k := range v {
    725 add(k)
    726 }
    727 })
    728 p.printMap("map[string]bool", v == nil, keys, func(k string) any { return v[k] }, verb)
    729 default:
    730 if verb == 'v' {
    731 p.padString(unhandled)
    732 } else {
    733 p.badVerb(verb)
    734 }
    735 }
    736}
    737
    738// printSlice prints "[a b]", or "[]T{a, b}" for %#v, each element with verb.
    739func (p *printer) printSlice(typ string, isNil bool, n int, at func(int) any, verb rune) {
    740 if p.sharpV {
    741 p.writeString(typ)
    742 if isNil {
    743 p.writeString(nilParen)
    744 return
    745 }
    746 p.writeByte('{')
    747 for i := 0; i < n; i++ {
    748 if i > 0 {
    749 p.writeString(commaSpace)
    750 }
    751 p.printElem(at(i), verb)
    752 }
    753 p.writeByte('}')
    754 return
    755 }
    756 p.writeByte('[')
    757 for i := 0; i < n; i++ {
    758 if i > 0 {
    759 p.writeByte(' ')
    760 }
    761 p.printElem(at(i), verb)
    762 }
    763 p.writeByte(']')
    764}
    765
    766// printMap prints "map[a:1 b:2]", or "map[string]int{"a":1, "b":2}" for %#v,
    767// keys sorted as Go sorts them.
    768func (p *printer) printMap(typ string, isNil bool, keys []string, at func(string) any, verb rune) {
    769 if p.sharpV {
    770 p.writeString(typ)
    771 if isNil {
    772 p.writeString(nilParen)
    773 return
    774 }
    775 p.writeByte('{')
    776 } else {
    777 p.writeString("map[")
    778 }
    779 for i, k := range keys {
    780 if i > 0 {
    781 if p.sharpV {
    782 p.writeString(commaSpace)
    783 } else {
    784 p.writeByte(' ')
    785 }
    786 }
    787 p.printElem(k, verb)
    788 p.writeByte(':')
    789 p.printElem(at(k), verb)
    790 }
    791 if p.sharpV {
    792 p.writeByte('}')
    793 } else {
    794 p.writeByte(']')
    795 }
    796}
    797
    798// printElem prints one element of a composite, keeping the outer operand for
    799// error messages. A nil element prints "<nil>" whatever the verb, as in Go.
    800func (p *printer) printElem(v any, verb rune) {
    801 outer := p.arg
    802 if v == nil {
    803 if p.sharpV {
    804 p.writeString("interface {}(nil)")
    805 } else {
    806 p.padString(nilAngle)
    807 }
    808 } else {
    809 p.printArg(v, verb)
    810 }
    811 p.arg = outer
    812}
    813
    814func sortedKeys(n int, each func(add func(string))) []string {
    815 keys := make([]string, 0, n)
    816 each(func(k string) { keys = append(keys, k) })
    817 sort.Strings(keys)
    818 return keys
    819}
    820
    821// typeName is %T for the types gno can name without reflect.
    822func typeName(v any) string {
    823 switch v.(type) {
    824 case bool:
    825 return "bool"
    826 case int:
    827 return "int"
    828 case int8:
    829 return "int8"
    830 case int16:
    831 return "int16"
    832 case int32:
    833 return "int32"
    834 case int64:
    835 return "int64"
    836 case uint:
    837 return "uint"
    838 case uint8:
    839 return "uint8"
    840 case uint16:
    841 return "uint16"
    842 case uint32:
    843 return "uint32"
    844 case uint64:
    845 return "uint64"
    846 case float32:
    847 return "float32"
    848 case float64:
    849 return "float64"
    850 case string:
    851 return "string"
    852 case []byte:
    853 return "[]uint8"
    854 case []any:
    855 return "[]interface {}"
    856 case []string:
    857 return "[]string"
    858 case []error:
    859 return "[]error"
    860 case []bool:
    861 return "[]bool"
    862 case []int:
    863 return "[]int"
    864 case []int8:
    865 return "[]int8"
    866 case []int16:
    867 return "[]int16"
    868 case []int32:
    869 return "[]int32"
    870 case []int64:
    871 return "[]int64"
    872 case []uint:
    873 return "[]uint"
    874 case []uint16:
    875 return "[]uint16"
    876 case []uint32:
    877 return "[]uint32"
    878 case []uint64:
    879 return "[]uint64"
    880 case []float32:
    881 return "[]float32"
    882 case []float64:
    883 return "[]float64"
    884 case map[string]string:
    885 return "map[string]string"
    886 case map[string]any:
    887 return "map[string]interface {}"
    888 case map[string]int:
    889 return "map[string]int"
    890 case map[string]bool:
    891 return "map[string]bool"
    892 }
    893 return "unknown"
    894}
    895