github.com/liquid-dev/text@v0.3.3-liquid/message/print.go (about)

     1  // Copyright 2017 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  package message
     6  
     7  import (
     8  	"bytes"
     9  	"fmt" // TODO: consider copying interfaces from package fmt to avoid dependency.
    10  	"math"
    11  	"reflect"
    12  	"sync"
    13  	"unicode/utf8"
    14  
    15  	"github.com/liquid-dev/text/internal/format"
    16  	"github.com/liquid-dev/text/internal/number"
    17  	"github.com/liquid-dev/text/language"
    18  	"github.com/liquid-dev/text/message/catalog"
    19  )
    20  
    21  // Strings for use with buffer.WriteString.
    22  // This is less overhead than using buffer.Write with byte arrays.
    23  const (
    24  	commaSpaceString  = ", "
    25  	nilAngleString    = "<nil>"
    26  	nilParenString    = "(nil)"
    27  	nilString         = "nil"
    28  	mapString         = "map["
    29  	percentBangString = "%!"
    30  	missingString     = "(MISSING)"
    31  	badIndexString    = "(BADINDEX)"
    32  	panicString       = "(PANIC="
    33  	extraString       = "%!(EXTRA "
    34  	badWidthString    = "%!(BADWIDTH)"
    35  	badPrecString     = "%!(BADPREC)"
    36  	noVerbString      = "%!(NOVERB)"
    37  
    38  	invReflectString = "<invalid reflect.Value>"
    39  )
    40  
    41  var printerPool = sync.Pool{
    42  	New: func() interface{} { return new(printer) },
    43  }
    44  
    45  // newPrinter allocates a new printer struct or grabs a cached one.
    46  func newPrinter(pp *Printer) *printer {
    47  	p := printerPool.Get().(*printer)
    48  	p.Printer = *pp
    49  	// TODO: cache most of the following call.
    50  	p.catContext = pp.cat.Context(pp.tag, p)
    51  
    52  	p.panicking = false
    53  	p.erroring = false
    54  	p.fmt.init(&p.Buffer)
    55  	return p
    56  }
    57  
    58  // free saves used printer structs in printerFree; avoids an allocation per invocation.
    59  func (p *printer) free() {
    60  	p.Buffer.Reset()
    61  	p.arg = nil
    62  	p.value = reflect.Value{}
    63  	printerPool.Put(p)
    64  }
    65  
    66  // printer is used to store a printer's state.
    67  // It implements "github.com/liquid-dev/text/internal/format".State.
    68  type printer struct {
    69  	Printer
    70  
    71  	// the context for looking up message translations
    72  	catContext *catalog.Context
    73  
    74  	// buffer for accumulating output.
    75  	bytes.Buffer
    76  
    77  	// arg holds the current item, as an interface{}.
    78  	arg interface{}
    79  	// value is used instead of arg for reflect values.
    80  	value reflect.Value
    81  
    82  	// fmt is used to format basic items such as integers or strings.
    83  	fmt formatInfo
    84  
    85  	// panicking is set by catchPanic to avoid infinite panic, recover, panic, ... recursion.
    86  	panicking bool
    87  	// erroring is set when printing an error string to guard against calling handleMethods.
    88  	erroring bool
    89  }
    90  
    91  // Language implements "github.com/liquid-dev/text/internal/format".State.
    92  func (p *printer) Language() language.Tag { return p.tag }
    93  
    94  func (p *printer) Width() (wid int, ok bool) { return p.fmt.Width, p.fmt.WidthPresent }
    95  
    96  func (p *printer) Precision() (prec int, ok bool) { return p.fmt.Prec, p.fmt.PrecPresent }
    97  
    98  func (p *printer) Flag(b int) bool {
    99  	switch b {
   100  	case '-':
   101  		return p.fmt.Minus
   102  	case '+':
   103  		return p.fmt.Plus || p.fmt.PlusV
   104  	case '#':
   105  		return p.fmt.Sharp || p.fmt.SharpV
   106  	case ' ':
   107  		return p.fmt.Space
   108  	case '0':
   109  		return p.fmt.Zero
   110  	}
   111  	return false
   112  }
   113  
   114  // getField gets the i'th field of the struct value.
   115  // If the field is itself is an interface, return a value for
   116  // the thing inside the interface, not the interface itself.
   117  func getField(v reflect.Value, i int) reflect.Value {
   118  	val := v.Field(i)
   119  	if val.Kind() == reflect.Interface && !val.IsNil() {
   120  		val = val.Elem()
   121  	}
   122  	return val
   123  }
   124  
   125  func (p *printer) unknownType(v reflect.Value) {
   126  	if !v.IsValid() {
   127  		p.WriteString(nilAngleString)
   128  		return
   129  	}
   130  	p.WriteByte('?')
   131  	p.WriteString(v.Type().String())
   132  	p.WriteByte('?')
   133  }
   134  
   135  func (p *printer) badVerb(verb rune) {
   136  	p.erroring = true
   137  	p.WriteString(percentBangString)
   138  	p.WriteRune(verb)
   139  	p.WriteByte('(')
   140  	switch {
   141  	case p.arg != nil:
   142  		p.WriteString(reflect.TypeOf(p.arg).String())
   143  		p.WriteByte('=')
   144  		p.printArg(p.arg, 'v')
   145  	case p.value.IsValid():
   146  		p.WriteString(p.value.Type().String())
   147  		p.WriteByte('=')
   148  		p.printValue(p.value, 'v', 0)
   149  	default:
   150  		p.WriteString(nilAngleString)
   151  	}
   152  	p.WriteByte(')')
   153  	p.erroring = false
   154  }
   155  
   156  func (p *printer) fmtBool(v bool, verb rune) {
   157  	switch verb {
   158  	case 't', 'v':
   159  		p.fmt.fmt_boolean(v)
   160  	default:
   161  		p.badVerb(verb)
   162  	}
   163  }
   164  
   165  // fmt0x64 formats a uint64 in hexadecimal and prefixes it with 0x or
   166  // not, as requested, by temporarily setting the sharp flag.
   167  func (p *printer) fmt0x64(v uint64, leading0x bool) {
   168  	sharp := p.fmt.Sharp
   169  	p.fmt.Sharp = leading0x
   170  	p.fmt.fmt_integer(v, 16, unsigned, ldigits)
   171  	p.fmt.Sharp = sharp
   172  }
   173  
   174  // fmtInteger formats a signed or unsigned integer.
   175  func (p *printer) fmtInteger(v uint64, isSigned bool, verb rune) {
   176  	switch verb {
   177  	case 'v':
   178  		if p.fmt.SharpV && !isSigned {
   179  			p.fmt0x64(v, true)
   180  			return
   181  		}
   182  		fallthrough
   183  	case 'd':
   184  		if p.fmt.Sharp || p.fmt.SharpV {
   185  			p.fmt.fmt_integer(v, 10, isSigned, ldigits)
   186  		} else {
   187  			p.fmtDecimalInt(v, isSigned)
   188  		}
   189  	case 'b':
   190  		p.fmt.fmt_integer(v, 2, isSigned, ldigits)
   191  	case 'o':
   192  		p.fmt.fmt_integer(v, 8, isSigned, ldigits)
   193  	case 'x':
   194  		p.fmt.fmt_integer(v, 16, isSigned, ldigits)
   195  	case 'X':
   196  		p.fmt.fmt_integer(v, 16, isSigned, udigits)
   197  	case 'c':
   198  		p.fmt.fmt_c(v)
   199  	case 'q':
   200  		if v <= utf8.MaxRune {
   201  			p.fmt.fmt_qc(v)
   202  		} else {
   203  			p.badVerb(verb)
   204  		}
   205  	case 'U':
   206  		p.fmt.fmt_unicode(v)
   207  	default:
   208  		p.badVerb(verb)
   209  	}
   210  }
   211  
   212  // fmtFloat formats a float. The default precision for each verb
   213  // is specified as last argument in the call to fmt_float.
   214  func (p *printer) fmtFloat(v float64, size int, verb rune) {
   215  	switch verb {
   216  	case 'b':
   217  		p.fmt.fmt_float(v, size, verb, -1)
   218  	case 'v':
   219  		verb = 'g'
   220  		fallthrough
   221  	case 'g', 'G':
   222  		if p.fmt.Sharp || p.fmt.SharpV {
   223  			p.fmt.fmt_float(v, size, verb, -1)
   224  		} else {
   225  			p.fmtVariableFloat(v, size)
   226  		}
   227  	case 'e', 'E':
   228  		if p.fmt.Sharp || p.fmt.SharpV {
   229  			p.fmt.fmt_float(v, size, verb, 6)
   230  		} else {
   231  			p.fmtScientific(v, size, 6)
   232  		}
   233  	case 'f', 'F':
   234  		if p.fmt.Sharp || p.fmt.SharpV {
   235  			p.fmt.fmt_float(v, size, verb, 6)
   236  		} else {
   237  			p.fmtDecimalFloat(v, size, 6)
   238  		}
   239  	default:
   240  		p.badVerb(verb)
   241  	}
   242  }
   243  
   244  func (p *printer) setFlags(f *number.Formatter) {
   245  	f.Flags &^= number.ElideSign
   246  	if p.fmt.Plus || p.fmt.Space {
   247  		f.Flags |= number.AlwaysSign
   248  		if !p.fmt.Plus {
   249  			f.Flags |= number.ElideSign
   250  		}
   251  	} else {
   252  		f.Flags &^= number.AlwaysSign
   253  	}
   254  }
   255  
   256  func (p *printer) updatePadding(f *number.Formatter) {
   257  	f.Flags &^= number.PadMask
   258  	if p.fmt.Minus {
   259  		f.Flags |= number.PadAfterSuffix
   260  	} else {
   261  		f.Flags |= number.PadBeforePrefix
   262  	}
   263  	f.PadRune = ' '
   264  	f.FormatWidth = uint16(p.fmt.Width)
   265  }
   266  
   267  func (p *printer) initDecimal(minFrac, maxFrac int) {
   268  	f := &p.toDecimal
   269  	f.MinIntegerDigits = 1
   270  	f.MaxIntegerDigits = 0
   271  	f.MinFractionDigits = uint8(minFrac)
   272  	f.MaxFractionDigits = int16(maxFrac)
   273  	p.setFlags(f)
   274  	f.PadRune = 0
   275  	if p.fmt.WidthPresent {
   276  		if p.fmt.Zero {
   277  			wid := p.fmt.Width
   278  			// Use significant integers for this.
   279  			// TODO: this is not the same as width, but so be it.
   280  			if f.MinFractionDigits > 0 {
   281  				wid -= 1 + int(f.MinFractionDigits)
   282  			}
   283  			if p.fmt.Plus || p.fmt.Space {
   284  				wid--
   285  			}
   286  			if wid > 0 && wid > int(f.MinIntegerDigits) {
   287  				f.MinIntegerDigits = uint8(wid)
   288  			}
   289  		}
   290  		p.updatePadding(f)
   291  	}
   292  }
   293  
   294  func (p *printer) initScientific(minFrac, maxFrac int) {
   295  	f := &p.toScientific
   296  	if maxFrac < 0 {
   297  		f.SetPrecision(maxFrac)
   298  	} else {
   299  		f.SetPrecision(maxFrac + 1)
   300  		f.MinFractionDigits = uint8(minFrac)
   301  		f.MaxFractionDigits = int16(maxFrac)
   302  	}
   303  	f.MinExponentDigits = 2
   304  	p.setFlags(f)
   305  	f.PadRune = 0
   306  	if p.fmt.WidthPresent {
   307  		f.Flags &^= number.PadMask
   308  		if p.fmt.Zero {
   309  			f.PadRune = f.Digit(0)
   310  			f.Flags |= number.PadAfterPrefix
   311  		} else {
   312  			f.PadRune = ' '
   313  			f.Flags |= number.PadBeforePrefix
   314  		}
   315  		p.updatePadding(f)
   316  	}
   317  }
   318  
   319  func (p *printer) fmtDecimalInt(v uint64, isSigned bool) {
   320  	var d number.Decimal
   321  
   322  	f := &p.toDecimal
   323  	if p.fmt.PrecPresent {
   324  		p.setFlags(f)
   325  		f.MinIntegerDigits = uint8(p.fmt.Prec)
   326  		f.MaxIntegerDigits = 0
   327  		f.MinFractionDigits = 0
   328  		f.MaxFractionDigits = 0
   329  		if p.fmt.WidthPresent {
   330  			p.updatePadding(f)
   331  		}
   332  	} else {
   333  		p.initDecimal(0, 0)
   334  	}
   335  	d.ConvertInt(p.toDecimal.RoundingContext, isSigned, v)
   336  
   337  	out := p.toDecimal.Format([]byte(nil), &d)
   338  	p.Buffer.Write(out)
   339  }
   340  
   341  func (p *printer) fmtDecimalFloat(v float64, size, prec int) {
   342  	var d number.Decimal
   343  	if p.fmt.PrecPresent {
   344  		prec = p.fmt.Prec
   345  	}
   346  	p.initDecimal(prec, prec)
   347  	d.ConvertFloat(p.toDecimal.RoundingContext, v, size)
   348  
   349  	out := p.toDecimal.Format([]byte(nil), &d)
   350  	p.Buffer.Write(out)
   351  }
   352  
   353  func (p *printer) fmtVariableFloat(v float64, size int) {
   354  	prec := -1
   355  	if p.fmt.PrecPresent {
   356  		prec = p.fmt.Prec
   357  	}
   358  	var d number.Decimal
   359  	p.initScientific(0, prec)
   360  	d.ConvertFloat(p.toScientific.RoundingContext, v, size)
   361  
   362  	// Copy logic of 'g' formatting from strconv. It is simplified a bit as
   363  	// we don't have to mind having prec > len(d.Digits).
   364  	shortest := prec < 0
   365  	ePrec := prec
   366  	if shortest {
   367  		prec = len(d.Digits)
   368  		ePrec = 6
   369  	} else if prec == 0 {
   370  		prec = 1
   371  		ePrec = 1
   372  	}
   373  	exp := int(d.Exp) - 1
   374  	if exp < -4 || exp >= ePrec {
   375  		p.initScientific(0, prec)
   376  
   377  		out := p.toScientific.Format([]byte(nil), &d)
   378  		p.Buffer.Write(out)
   379  	} else {
   380  		if prec > int(d.Exp) {
   381  			prec = len(d.Digits)
   382  		}
   383  		if prec -= int(d.Exp); prec < 0 {
   384  			prec = 0
   385  		}
   386  		p.initDecimal(0, prec)
   387  
   388  		out := p.toDecimal.Format([]byte(nil), &d)
   389  		p.Buffer.Write(out)
   390  	}
   391  }
   392  
   393  func (p *printer) fmtScientific(v float64, size, prec int) {
   394  	var d number.Decimal
   395  	if p.fmt.PrecPresent {
   396  		prec = p.fmt.Prec
   397  	}
   398  	p.initScientific(prec, prec)
   399  	rc := p.toScientific.RoundingContext
   400  	d.ConvertFloat(rc, v, size)
   401  
   402  	out := p.toScientific.Format([]byte(nil), &d)
   403  	p.Buffer.Write(out)
   404  
   405  }
   406  
   407  // fmtComplex formats a complex number v with
   408  // r = real(v) and j = imag(v) as (r+ji) using
   409  // fmtFloat for r and j formatting.
   410  func (p *printer) fmtComplex(v complex128, size int, verb rune) {
   411  	// Make sure any unsupported verbs are found before the
   412  	// calls to fmtFloat to not generate an incorrect error string.
   413  	switch verb {
   414  	case 'v', 'b', 'g', 'G', 'f', 'F', 'e', 'E':
   415  		p.WriteByte('(')
   416  		p.fmtFloat(real(v), size/2, verb)
   417  		// Imaginary part always has a sign.
   418  		if math.IsNaN(imag(v)) {
   419  			// By CLDR's rules, NaNs do not use patterns or signs. As this code
   420  			// relies on AlwaysSign working for imaginary parts, we need to
   421  			// manually handle NaNs.
   422  			f := &p.toScientific
   423  			p.setFlags(f)
   424  			p.updatePadding(f)
   425  			p.setFlags(f)
   426  			nan := f.Symbol(number.SymNan)
   427  			extra := 0
   428  			if w, ok := p.Width(); ok {
   429  				extra = w - utf8.RuneCountInString(nan) - 1
   430  			}
   431  			if f.Flags&number.PadAfterNumber == 0 {
   432  				for ; extra > 0; extra-- {
   433  					p.WriteRune(f.PadRune)
   434  				}
   435  			}
   436  			p.WriteString(f.Symbol(number.SymPlusSign))
   437  			p.WriteString(nan)
   438  			for ; extra > 0; extra-- {
   439  				p.WriteRune(f.PadRune)
   440  			}
   441  			p.WriteString("i)")
   442  			return
   443  		}
   444  		oldPlus := p.fmt.Plus
   445  		p.fmt.Plus = true
   446  		p.fmtFloat(imag(v), size/2, verb)
   447  		p.WriteString("i)") // TODO: use symbol?
   448  		p.fmt.Plus = oldPlus
   449  	default:
   450  		p.badVerb(verb)
   451  	}
   452  }
   453  
   454  func (p *printer) fmtString(v string, verb rune) {
   455  	switch verb {
   456  	case 'v':
   457  		if p.fmt.SharpV {
   458  			p.fmt.fmt_q(v)
   459  		} else {
   460  			p.fmt.fmt_s(v)
   461  		}
   462  	case 's':
   463  		p.fmt.fmt_s(v)
   464  	case 'x':
   465  		p.fmt.fmt_sx(v, ldigits)
   466  	case 'X':
   467  		p.fmt.fmt_sx(v, udigits)
   468  	case 'q':
   469  		p.fmt.fmt_q(v)
   470  	case 'm':
   471  		ctx := p.cat.Context(p.tag, rawPrinter{p})
   472  		if ctx.Execute(v) == catalog.ErrNotFound {
   473  			p.WriteString(v)
   474  		}
   475  	default:
   476  		p.badVerb(verb)
   477  	}
   478  }
   479  
   480  func (p *printer) fmtBytes(v []byte, verb rune, typeString string) {
   481  	switch verb {
   482  	case 'v', 'd':
   483  		if p.fmt.SharpV {
   484  			p.WriteString(typeString)
   485  			if v == nil {
   486  				p.WriteString(nilParenString)
   487  				return
   488  			}
   489  			p.WriteByte('{')
   490  			for i, c := range v {
   491  				if i > 0 {
   492  					p.WriteString(commaSpaceString)
   493  				}
   494  				p.fmt0x64(uint64(c), true)
   495  			}
   496  			p.WriteByte('}')
   497  		} else {
   498  			p.WriteByte('[')
   499  			for i, c := range v {
   500  				if i > 0 {
   501  					p.WriteByte(' ')
   502  				}
   503  				p.fmt.fmt_integer(uint64(c), 10, unsigned, ldigits)
   504  			}
   505  			p.WriteByte(']')
   506  		}
   507  	case 's':
   508  		p.fmt.fmt_s(string(v))
   509  	case 'x':
   510  		p.fmt.fmt_bx(v, ldigits)
   511  	case 'X':
   512  		p.fmt.fmt_bx(v, udigits)
   513  	case 'q':
   514  		p.fmt.fmt_q(string(v))
   515  	default:
   516  		p.printValue(reflect.ValueOf(v), verb, 0)
   517  	}
   518  }
   519  
   520  func (p *printer) fmtPointer(value reflect.Value, verb rune) {
   521  	var u uintptr
   522  	switch value.Kind() {
   523  	case reflect.Chan, reflect.Func, reflect.Map, reflect.Ptr, reflect.Slice, reflect.UnsafePointer:
   524  		u = value.Pointer()
   525  	default:
   526  		p.badVerb(verb)
   527  		return
   528  	}
   529  
   530  	switch verb {
   531  	case 'v':
   532  		if p.fmt.SharpV {
   533  			p.WriteByte('(')
   534  			p.WriteString(value.Type().String())
   535  			p.WriteString(")(")
   536  			if u == 0 {
   537  				p.WriteString(nilString)
   538  			} else {
   539  				p.fmt0x64(uint64(u), true)
   540  			}
   541  			p.WriteByte(')')
   542  		} else {
   543  			if u == 0 {
   544  				p.fmt.padString(nilAngleString)
   545  			} else {
   546  				p.fmt0x64(uint64(u), !p.fmt.Sharp)
   547  			}
   548  		}
   549  	case 'p':
   550  		p.fmt0x64(uint64(u), !p.fmt.Sharp)
   551  	case 'b', 'o', 'd', 'x', 'X':
   552  		if verb == 'd' {
   553  			p.fmt.Sharp = true // Print as standard go. TODO: does this make sense?
   554  		}
   555  		p.fmtInteger(uint64(u), unsigned, verb)
   556  	default:
   557  		p.badVerb(verb)
   558  	}
   559  }
   560  
   561  func (p *printer) catchPanic(arg interface{}, verb rune) {
   562  	if err := recover(); err != nil {
   563  		// If it's a nil pointer, just say "<nil>". The likeliest causes are a
   564  		// Stringer that fails to guard against nil or a nil pointer for a
   565  		// value receiver, and in either case, "<nil>" is a nice result.
   566  		if v := reflect.ValueOf(arg); v.Kind() == reflect.Ptr && v.IsNil() {
   567  			p.WriteString(nilAngleString)
   568  			return
   569  		}
   570  		// Otherwise print a concise panic message. Most of the time the panic
   571  		// value will print itself nicely.
   572  		if p.panicking {
   573  			// Nested panics; the recursion in printArg cannot succeed.
   574  			panic(err)
   575  		}
   576  
   577  		oldFlags := p.fmt.Parser
   578  		// For this output we want default behavior.
   579  		p.fmt.ClearFlags()
   580  
   581  		p.WriteString(percentBangString)
   582  		p.WriteRune(verb)
   583  		p.WriteString(panicString)
   584  		p.panicking = true
   585  		p.printArg(err, 'v')
   586  		p.panicking = false
   587  		p.WriteByte(')')
   588  
   589  		p.fmt.Parser = oldFlags
   590  	}
   591  }
   592  
   593  func (p *printer) handleMethods(verb rune) (handled bool) {
   594  	if p.erroring {
   595  		return
   596  	}
   597  	// Is it a Formatter?
   598  	if formatter, ok := p.arg.(format.Formatter); ok {
   599  		handled = true
   600  		defer p.catchPanic(p.arg, verb)
   601  		formatter.Format(p, verb)
   602  		return
   603  	}
   604  	if formatter, ok := p.arg.(fmt.Formatter); ok {
   605  		handled = true
   606  		defer p.catchPanic(p.arg, verb)
   607  		formatter.Format(p, verb)
   608  		return
   609  	}
   610  
   611  	// If we're doing Go syntax and the argument knows how to supply it, take care of it now.
   612  	if p.fmt.SharpV {
   613  		if stringer, ok := p.arg.(fmt.GoStringer); ok {
   614  			handled = true
   615  			defer p.catchPanic(p.arg, verb)
   616  			// Print the result of GoString unadorned.
   617  			p.fmt.fmt_s(stringer.GoString())
   618  			return
   619  		}
   620  	} else {
   621  		// If a string is acceptable according to the format, see if
   622  		// the value satisfies one of the string-valued interfaces.
   623  		// Println etc. set verb to %v, which is "stringable".
   624  		switch verb {
   625  		case 'v', 's', 'x', 'X', 'q':
   626  			// Is it an error or Stringer?
   627  			// The duplication in the bodies is necessary:
   628  			// setting handled and deferring catchPanic
   629  			// must happen before calling the method.
   630  			switch v := p.arg.(type) {
   631  			case error:
   632  				handled = true
   633  				defer p.catchPanic(p.arg, verb)
   634  				p.fmtString(v.Error(), verb)
   635  				return
   636  
   637  			case fmt.Stringer:
   638  				handled = true
   639  				defer p.catchPanic(p.arg, verb)
   640  				p.fmtString(v.String(), verb)
   641  				return
   642  			}
   643  		}
   644  	}
   645  	return false
   646  }
   647  
   648  func (p *printer) printArg(arg interface{}, verb rune) {
   649  	p.arg = arg
   650  	p.value = reflect.Value{}
   651  
   652  	if arg == nil {
   653  		switch verb {
   654  		case 'T', 'v':
   655  			p.fmt.padString(nilAngleString)
   656  		default:
   657  			p.badVerb(verb)
   658  		}
   659  		return
   660  	}
   661  
   662  	// Special processing considerations.
   663  	// %T (the value's type) and %p (its address) are special; we always do them first.
   664  	switch verb {
   665  	case 'T':
   666  		p.fmt.fmt_s(reflect.TypeOf(arg).String())
   667  		return
   668  	case 'p':
   669  		p.fmtPointer(reflect.ValueOf(arg), 'p')
   670  		return
   671  	}
   672  
   673  	// Some types can be done without reflection.
   674  	switch f := arg.(type) {
   675  	case bool:
   676  		p.fmtBool(f, verb)
   677  	case float32:
   678  		p.fmtFloat(float64(f), 32, verb)
   679  	case float64:
   680  		p.fmtFloat(f, 64, verb)
   681  	case complex64:
   682  		p.fmtComplex(complex128(f), 64, verb)
   683  	case complex128:
   684  		p.fmtComplex(f, 128, verb)
   685  	case int:
   686  		p.fmtInteger(uint64(f), signed, verb)
   687  	case int8:
   688  		p.fmtInteger(uint64(f), signed, verb)
   689  	case int16:
   690  		p.fmtInteger(uint64(f), signed, verb)
   691  	case int32:
   692  		p.fmtInteger(uint64(f), signed, verb)
   693  	case int64:
   694  		p.fmtInteger(uint64(f), signed, verb)
   695  	case uint:
   696  		p.fmtInteger(uint64(f), unsigned, verb)
   697  	case uint8:
   698  		p.fmtInteger(uint64(f), unsigned, verb)
   699  	case uint16:
   700  		p.fmtInteger(uint64(f), unsigned, verb)
   701  	case uint32:
   702  		p.fmtInteger(uint64(f), unsigned, verb)
   703  	case uint64:
   704  		p.fmtInteger(f, unsigned, verb)
   705  	case uintptr:
   706  		p.fmtInteger(uint64(f), unsigned, verb)
   707  	case string:
   708  		p.fmtString(f, verb)
   709  	case []byte:
   710  		p.fmtBytes(f, verb, "[]byte")
   711  	case reflect.Value:
   712  		// Handle extractable values with special methods
   713  		// since printValue does not handle them at depth 0.
   714  		if f.IsValid() && f.CanInterface() {
   715  			p.arg = f.Interface()
   716  			if p.handleMethods(verb) {
   717  				return
   718  			}
   719  		}
   720  		p.printValue(f, verb, 0)
   721  	default:
   722  		// If the type is not simple, it might have methods.
   723  		if !p.handleMethods(verb) {
   724  			// Need to use reflection, since the type had no
   725  			// interface methods that could be used for formatting.
   726  			p.printValue(reflect.ValueOf(f), verb, 0)
   727  		}
   728  	}
   729  }
   730  
   731  // printValue is similar to printArg but starts with a reflect value, not an interface{} value.
   732  // It does not handle 'p' and 'T' verbs because these should have been already handled by printArg.
   733  func (p *printer) printValue(value reflect.Value, verb rune, depth int) {
   734  	// Handle values with special methods if not already handled by printArg (depth == 0).
   735  	if depth > 0 && value.IsValid() && value.CanInterface() {
   736  		p.arg = value.Interface()
   737  		if p.handleMethods(verb) {
   738  			return
   739  		}
   740  	}
   741  	p.arg = nil
   742  	p.value = value
   743  
   744  	switch f := value; value.Kind() {
   745  	case reflect.Invalid:
   746  		if depth == 0 {
   747  			p.WriteString(invReflectString)
   748  		} else {
   749  			switch verb {
   750  			case 'v':
   751  				p.WriteString(nilAngleString)
   752  			default:
   753  				p.badVerb(verb)
   754  			}
   755  		}
   756  	case reflect.Bool:
   757  		p.fmtBool(f.Bool(), verb)
   758  	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
   759  		p.fmtInteger(uint64(f.Int()), signed, verb)
   760  	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
   761  		p.fmtInteger(f.Uint(), unsigned, verb)
   762  	case reflect.Float32:
   763  		p.fmtFloat(f.Float(), 32, verb)
   764  	case reflect.Float64:
   765  		p.fmtFloat(f.Float(), 64, verb)
   766  	case reflect.Complex64:
   767  		p.fmtComplex(f.Complex(), 64, verb)
   768  	case reflect.Complex128:
   769  		p.fmtComplex(f.Complex(), 128, verb)
   770  	case reflect.String:
   771  		p.fmtString(f.String(), verb)
   772  	case reflect.Map:
   773  		if p.fmt.SharpV {
   774  			p.WriteString(f.Type().String())
   775  			if f.IsNil() {
   776  				p.WriteString(nilParenString)
   777  				return
   778  			}
   779  			p.WriteByte('{')
   780  		} else {
   781  			p.WriteString(mapString)
   782  		}
   783  		keys := f.MapKeys()
   784  		for i, key := range keys {
   785  			if i > 0 {
   786  				if p.fmt.SharpV {
   787  					p.WriteString(commaSpaceString)
   788  				} else {
   789  					p.WriteByte(' ')
   790  				}
   791  			}
   792  			p.printValue(key, verb, depth+1)
   793  			p.WriteByte(':')
   794  			p.printValue(f.MapIndex(key), verb, depth+1)
   795  		}
   796  		if p.fmt.SharpV {
   797  			p.WriteByte('}')
   798  		} else {
   799  			p.WriteByte(']')
   800  		}
   801  	case reflect.Struct:
   802  		if p.fmt.SharpV {
   803  			p.WriteString(f.Type().String())
   804  		}
   805  		p.WriteByte('{')
   806  		for i := 0; i < f.NumField(); i++ {
   807  			if i > 0 {
   808  				if p.fmt.SharpV {
   809  					p.WriteString(commaSpaceString)
   810  				} else {
   811  					p.WriteByte(' ')
   812  				}
   813  			}
   814  			if p.fmt.PlusV || p.fmt.SharpV {
   815  				if name := f.Type().Field(i).Name; name != "" {
   816  					p.WriteString(name)
   817  					p.WriteByte(':')
   818  				}
   819  			}
   820  			p.printValue(getField(f, i), verb, depth+1)
   821  		}
   822  		p.WriteByte('}')
   823  	case reflect.Interface:
   824  		value := f.Elem()
   825  		if !value.IsValid() {
   826  			if p.fmt.SharpV {
   827  				p.WriteString(f.Type().String())
   828  				p.WriteString(nilParenString)
   829  			} else {
   830  				p.WriteString(nilAngleString)
   831  			}
   832  		} else {
   833  			p.printValue(value, verb, depth+1)
   834  		}
   835  	case reflect.Array, reflect.Slice:
   836  		switch verb {
   837  		case 's', 'q', 'x', 'X':
   838  			// Handle byte and uint8 slices and arrays special for the above verbs.
   839  			t := f.Type()
   840  			if t.Elem().Kind() == reflect.Uint8 {
   841  				var bytes []byte
   842  				if f.Kind() == reflect.Slice {
   843  					bytes = f.Bytes()
   844  				} else if f.CanAddr() {
   845  					bytes = f.Slice(0, f.Len()).Bytes()
   846  				} else {
   847  					// We have an array, but we cannot Slice() a non-addressable array,
   848  					// so we build a slice by hand. This is a rare case but it would be nice
   849  					// if reflection could help a little more.
   850  					bytes = make([]byte, f.Len())
   851  					for i := range bytes {
   852  						bytes[i] = byte(f.Index(i).Uint())
   853  					}
   854  				}
   855  				p.fmtBytes(bytes, verb, t.String())
   856  				return
   857  			}
   858  		}
   859  		if p.fmt.SharpV {
   860  			p.WriteString(f.Type().String())
   861  			if f.Kind() == reflect.Slice && f.IsNil() {
   862  				p.WriteString(nilParenString)
   863  				return
   864  			}
   865  			p.WriteByte('{')
   866  			for i := 0; i < f.Len(); i++ {
   867  				if i > 0 {
   868  					p.WriteString(commaSpaceString)
   869  				}
   870  				p.printValue(f.Index(i), verb, depth+1)
   871  			}
   872  			p.WriteByte('}')
   873  		} else {
   874  			p.WriteByte('[')
   875  			for i := 0; i < f.Len(); i++ {
   876  				if i > 0 {
   877  					p.WriteByte(' ')
   878  				}
   879  				p.printValue(f.Index(i), verb, depth+1)
   880  			}
   881  			p.WriteByte(']')
   882  		}
   883  	case reflect.Ptr:
   884  		// pointer to array or slice or struct?  ok at top level
   885  		// but not embedded (avoid loops)
   886  		if depth == 0 && f.Pointer() != 0 {
   887  			switch a := f.Elem(); a.Kind() {
   888  			case reflect.Array, reflect.Slice, reflect.Struct, reflect.Map:
   889  				p.WriteByte('&')
   890  				p.printValue(a, verb, depth+1)
   891  				return
   892  			}
   893  		}
   894  		fallthrough
   895  	case reflect.Chan, reflect.Func, reflect.UnsafePointer:
   896  		p.fmtPointer(f, verb)
   897  	default:
   898  		p.unknownType(f)
   899  	}
   900  }
   901  
   902  func (p *printer) badArgNum(verb rune) {
   903  	p.WriteString(percentBangString)
   904  	p.WriteRune(verb)
   905  	p.WriteString(badIndexString)
   906  }
   907  
   908  func (p *printer) missingArg(verb rune) {
   909  	p.WriteString(percentBangString)
   910  	p.WriteRune(verb)
   911  	p.WriteString(missingString)
   912  }
   913  
   914  func (p *printer) doPrintf(fmt string) {
   915  	for p.fmt.Parser.SetFormat(fmt); p.fmt.Scan(); {
   916  		switch p.fmt.Status {
   917  		case format.StatusText:
   918  			p.WriteString(p.fmt.Text())
   919  		case format.StatusSubstitution:
   920  			p.printArg(p.Arg(p.fmt.ArgNum), p.fmt.Verb)
   921  		case format.StatusBadWidthSubstitution:
   922  			p.WriteString(badWidthString)
   923  			p.printArg(p.Arg(p.fmt.ArgNum), p.fmt.Verb)
   924  		case format.StatusBadPrecSubstitution:
   925  			p.WriteString(badPrecString)
   926  			p.printArg(p.Arg(p.fmt.ArgNum), p.fmt.Verb)
   927  		case format.StatusNoVerb:
   928  			p.WriteString(noVerbString)
   929  		case format.StatusBadArgNum:
   930  			p.badArgNum(p.fmt.Verb)
   931  		case format.StatusMissingArg:
   932  			p.missingArg(p.fmt.Verb)
   933  		default:
   934  			panic("unreachable")
   935  		}
   936  	}
   937  
   938  	// Check for extra arguments, but only if there was at least one ordered
   939  	// argument. Note that this behavior is necessarily different from fmt:
   940  	// different variants of messages may opt to drop some or all of the
   941  	// arguments.
   942  	if !p.fmt.Reordered && p.fmt.ArgNum < len(p.fmt.Args) && p.fmt.ArgNum != 0 {
   943  		p.fmt.ClearFlags()
   944  		p.WriteString(extraString)
   945  		for i, arg := range p.fmt.Args[p.fmt.ArgNum:] {
   946  			if i > 0 {
   947  				p.WriteString(commaSpaceString)
   948  			}
   949  			if arg == nil {
   950  				p.WriteString(nilAngleString)
   951  			} else {
   952  				p.WriteString(reflect.TypeOf(arg).String())
   953  				p.WriteString("=")
   954  				p.printArg(arg, 'v')
   955  			}
   956  		}
   957  		p.WriteByte(')')
   958  	}
   959  }
   960  
   961  func (p *printer) doPrint(a []interface{}) {
   962  	prevString := false
   963  	for argNum, arg := range a {
   964  		isString := arg != nil && reflect.TypeOf(arg).Kind() == reflect.String
   965  		// Add a space between two non-string arguments.
   966  		if argNum > 0 && !isString && !prevString {
   967  			p.WriteByte(' ')
   968  		}
   969  		p.printArg(arg, 'v')
   970  		prevString = isString
   971  	}
   972  }
   973  
   974  // doPrintln is like doPrint but always adds a space between arguments
   975  // and a newline after the last argument.
   976  func (p *printer) doPrintln(a []interface{}) {
   977  	for argNum, arg := range a {
   978  		if argNum > 0 {
   979  			p.WriteByte(' ')
   980  		}
   981  		p.printArg(arg, 'v')
   982  	}
   983  	p.WriteByte('\n')
   984  }