]> Cypherpunks repositories - gostls13.git/commitdiff
fmt: change evalutation of indexed arg to match docs
authorRob Pike <r@golang.org>
Wed, 29 May 2013 15:29:29 +0000 (11:29 -0400)
committerRob Pike <r@golang.org>
Wed, 29 May 2013 15:29:29 +0000 (11:29 -0400)
The old code put the index before the period in the precision;
it should be after so it's always before the star, as documented.
A little trickier to do in one pass but compensated for by more
tests and catching a couple of other error cases.

R=rsc
CC=golang-dev
https://golang.org/cl/9751044

src/pkg/fmt/doc.go
src/pkg/fmt/fmt_test.go
src/pkg/fmt/print.go

index a0c6795d81669d8f1da62cc60a2a15d51a6295ed..2910198508770e2eb9ea64a6d94d71f302799d8e 100644 (file)
        For example,
                fmt.Sprintf("%[2]d %[1]d\n", 11, 22)
        will yield "22, 11", while
-               fmt.Sprintf("%[3]*[2].*[1]f", 12.0, 2, 6),
+               fmt.Sprintf("%[3]*.[2]*[1]f", 12.0, 2, 6),
        equivalent to
                fmt.Sprintf("%6.2f", 12.0),
        will yield " 12.00". Because an explicit index affects subsequent verbs,
                Non-int for width or precision: %!(BADWIDTH) or %!(BADPREC)
                        Printf("%*s", 4.5, "hi"):  %!(BADWIDTH)hi
                        Printf("%.*s", 4.5, "hi"): %!(BADPREC)hi
-               Invalid or out-of-range argument index: %!(BADARGNUM)
-                       Printf("%*[2]d", 7):       %d(BADARGNUM)
+               Invalid or invalid use of argument index: %!(BADINDEX)
+                       Printf("%*[2]d", 7):       %d(BADINDEX)
+                       Printf("%.[2]d", 7):       %d(BADINDEX)
 
        All errors begin with the string "%!" followed sometimes
        by a single character (the verb) and end with a parenthesized
index a121c9c2480081ae3fefa294dae2a35ddf370402..85173aa4bc555fb46ca64577631c15e75e588053 100644 (file)
@@ -550,18 +550,29 @@ var reorderTests = []struct {
        {"%[2]d", SE{2, 1}, "1"},
        {"%[2]d %[1]d", SE{1, 2}, "2 1"},
        {"%[2]*[1]d", SE{2, 5}, "    2"},
-       {"%6.2f", SE{12.0}, " 12.00"},
-       {"%[3]*[2].*[1]f", SE{12.0, 2, 6}, " 12.00"},
-       {"%[1]*[2].*[3]f", SE{6, 2, 12.0}, " 12.00"},
+       {"%6.2f", SE{12.0}, " 12.00"}, // Explicit version of next line.
+       {"%[3]*.[2]*[1]f", SE{12.0, 2, 6}, " 12.00"},
+       {"%[1]*.[2]*[3]f", SE{6, 2, 12.0}, " 12.00"},
+       {"%10f", SE{12.0}, " 12.000000"},
+       {"%[1]*[3]f", SE{10, 99, 12.0}, " 12.000000"},
+       {"%.6f", SE{12.0}, "12.000000"}, // Explicit version of next line.
+       {"%.[1]*[3]f", SE{6, 99, 12.0}, "12.000000"},
+       {"%6.f", SE{12.0}, "    12"}, //  // Explicit version of next line; empty precision means zero.
+       {"%[1]*.[3]f", SE{6, 3, 12.0}, "    12"},
        // An actual use! Print the same arguments twice.
        {"%d %d %d %#[1]o %#o %#o", SE{11, 12, 13}, "11 12 13 013 014 015"},
 
        // Erroneous cases.
-       {"%[]d", SE{2, 1}, "%d(BADARGNUM)"},
-       {"%[-3]d", SE{2, 1}, "%d(BADARGNUM)"},
-       {"%[x]d", SE{2, 1}, "%d(BADARGNUM)"},
-       {"%[23]d", SE{2, 1}, "%d(BADARGNUM)"},
+       {"%[d", SE{2, 1}, "%d(BADINDEX)"},
+       {"%]d", SE{2, 1}, "%!](int=2)d%!(EXTRA int=1)"},
+       {"%[]d", SE{2, 1}, "%d(BADINDEX)"},
+       {"%[-3]d", SE{2, 1}, "%d(BADINDEX)"},
+       {"%[99]d", SE{2, 1}, "%d(BADINDEX)"},
        {"%[3]", SE{2, 1}, "%!(NOVERB)"},
+       {"%[1].2d", SE{5, 6}, "%d(BADINDEX)"},
+       {"%[1]2d", SE{2, 1}, "%d(BADINDEX)"},
+       {"%3.[2]d", SE{7}, "%d(BADINDEX)"},
+       {"%.[2]d", SE{7}, "%d(BADINDEX)"},
        {"%d %d %d %#[1]o %#o %#o %#o", SE{11, 12, 13}, "11 12 13 013 014 015 %o(MISSING)"},
 }
 
index 58ffe216e9e5973512aa9db72eabccf184d623c3..fa9eb52c6ad06a32d8e501f4ebeddfad0408e7e9 100644 (file)
@@ -22,7 +22,7 @@ var (
        nilBytes        = []byte("nil")
        mapBytes        = []byte("map[")
        missingBytes    = []byte("(MISSING)")
-       badArgNum       = []byte("(BADARGNUM)")
+       badIndexBytes   = []byte("(BADINDEX)")
        panicBytes      = []byte("(PANIC=")
        extraBytes      = []byte("%!(EXTRA ")
        irparenBytes    = []byte("i)")
@@ -117,7 +117,7 @@ type pp struct {
        value reflect.Value
        // reordered records whether the format string used argument reordering.
        reordered bool
-       // goodArgNum records whether the last reordering directive was valid.
+       // goodArgNum records whether all reordering directives were valid.
        goodArgNum bool
        runeBuf    [utf8.UTFMax]byte
        fmt        fmt
@@ -1021,11 +1021,11 @@ BigSwitch:
 }
 
 // intFromArg gets the argNumth element of a. On return, isInt reports whether the argument has type int.
-func intFromArg(a []interface{}, end, i, argNum int) (num int, isInt bool, newi, newArgNum int) {
-       newi, newArgNum = end, argNum
-       if i < end && argNum < len(a) {
+func intFromArg(a []interface{}, argNum int) (num int, isInt bool, newArgNum int) {
+       newArgNum = argNum
+       if argNum < len(a) {
                num, isInt = a[argNum].(int)
-               newi, newArgNum = i+1, argNum+1
+               newArgNum = argNum + 1
        }
        return
 }
@@ -1053,24 +1053,25 @@ func parseArgNumber(format string) (index int, wid int, ok bool) {
 // argNumber returns the next argument to evaluate, which is either the value of the passed-in
 // argNum or the value of the bracketed integer that begins format[i:]. It also returns
 // the new value of i, that is, the index of the next byte of the format to process.
-func (p *pp) argNumber(argNum int, format string, i int, numArgs int) (newArgNum, newi int) {
-       p.goodArgNum = true
+func (p *pp) argNumber(argNum int, format string, i int, numArgs int) (newArgNum, newi int, found bool) {
        if len(format) <= i || format[i] != '[' {
-               return argNum, i
+               return argNum, i, false
        }
        p.reordered = true
        index, wid, ok := parseArgNumber(format[i:])
        if ok && 0 <= index && index < numArgs {
-               return index, i + wid
+               return index, i + wid, true
        }
        p.goodArgNum = false
-       return argNum, i + wid
+       return argNum, i + wid, true
 }
 
 func (p *pp) doPrintf(format string, a []interface{}) {
        end := len(format)
-       argNum := 0 // we process one argument per non-trivial format
+       argNum := 0         // we process one argument per non-trivial format
+       afterIndex := false // previous item in format was an index like [3].
        p.reordered = false
+       p.goodArgNum = true
        for i := 0; i < end; {
                lasti := i
                for i < end && format[i] != '%' {
@@ -1108,35 +1109,50 @@ func (p *pp) doPrintf(format string, a []interface{}) {
                }
 
                // Do we have an explicit argument index?
-               argNum, i = p.argNumber(argNum, format, i, len(a))
+               argNum, i, afterIndex = p.argNumber(argNum, format, i, len(a))
 
                // Do we have width?
                if i < end && format[i] == '*' {
-                       p.fmt.wid, p.fmt.widPresent, i, argNum = intFromArg(a, end, i, argNum)
+                       i++
+                       p.fmt.wid, p.fmt.widPresent, argNum = intFromArg(a, argNum)
                        if !p.fmt.widPresent {
                                p.buf.Write(badWidthBytes)
                        }
-                       argNum, i = p.argNumber(argNum, format, i, len(a)) // We consumed []; another can follow here.
+                       afterIndex = false
                } else {
                        p.fmt.wid, p.fmt.widPresent, i = parsenum(format, i, end)
+                       if afterIndex && p.fmt.widPresent { // "%[3]2d"
+                               p.goodArgNum = false
+                       }
                }
 
                // Do we have precision?
                if i+1 < end && format[i] == '.' {
-                       if format[i+1] == '*' {
-                               p.fmt.prec, p.fmt.precPresent, i, argNum = intFromArg(a, end, i+1, argNum)
+                       i++
+                       if afterIndex { // "%[3].2d"
+                               p.goodArgNum = false
+                       }
+                       argNum, i, afterIndex = p.argNumber(argNum, format, i, len(a))
+                       if format[i] == '*' {
+                               i++
+                               p.fmt.prec, p.fmt.precPresent, argNum = intFromArg(a, argNum)
                                if !p.fmt.precPresent {
                                        p.buf.Write(badPrecBytes)
                                }
-                               argNum, i = p.argNumber(argNum, format, i, len(a)) // We consumed []; another can follow here.
+                               afterIndex = false
                        } else {
-                               p.fmt.prec, p.fmt.precPresent, i = parsenum(format, i+1, end)
+                               p.fmt.prec, p.fmt.precPresent, i = parsenum(format, i, end)
                                if !p.fmt.precPresent {
                                        p.fmt.prec = 0
                                        p.fmt.precPresent = true
                                }
                        }
                }
+
+               if !afterIndex {
+                       argNum, i, afterIndex = p.argNumber(argNum, format, i, len(a))
+               }
+
                if i >= end {
                        p.buf.Write(noVerbBytes)
                        continue
@@ -1151,7 +1167,7 @@ func (p *pp) doPrintf(format string, a []interface{}) {
                if !p.goodArgNum {
                        p.buf.WriteByte('%')
                        p.add(c)
-                       p.buf.Write(badArgNum)
+                       p.buf.Write(badIndexBytes)
                        continue
                } else if argNum >= len(a) { // out of operands
                        p.buf.WriteByte('%')