this repo has no description
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

pkg/strconv: allow string argument for FormatFloat format parameter

FormatFloat now accepts either a string ("g", "f", etc.) or an integer
(the byte value) for the format parameter. The function signature uses
cue.Value, which the generator maps to adt.TopKind.

This is a re-do of https://cuelang.org/cl/537569,
which was reverted right after being merged as it broke `go generate`.
The original fix moved FormatFloat into manual.go with a custom
builtin registration, but the generator still found the exported
function and produced a conflicting registration in pkg.go.
This version avoids the conflict by using cue.Value in the exported
Go signature, which the generator handles natively.

Using the wider cue.Value parameter does lead to values like -1 or 300
being allowed as arguments, so add a check against the range [0, 255]
to make sure that they continue giving an error.

Fixes #1436.

Signed-off-by: Daniel Martí <mvdan@mvdan.cc>
Change-Id: I014f7cdb5033d9c4fa15f7c8d194f9a915872ca9
Reviewed-on: https://review.gerrithub.io/c/cue-lang/cue/+/1233875
Unity-Result: CUE porcuepine <cue.porcuepine@gmail.com>
Reviewed-by: Roger Peppe <rogpeppe@gmail.com>
TryBot-Result: CUEcueckoo <cueckoo@cuelang.org>

+140 -73
+3 -3
pkg/strconv/pkg.go
··· 122 122 Name: "FormatFloat", 123 123 Params: []pkg.Param{ 124 124 {Kind: adt.NumberKind}, 125 - {Kind: adt.IntKind}, 125 + {Kind: adt.TopKind}, 126 126 {Kind: adt.IntKind}, 127 127 {Kind: adt.IntKind}, 128 128 }, 129 129 Result: adt.StringKind, 130 130 Func: func(c *pkg.CallCtxt) { 131 - f, fmt, prec, bitSize := c.Float64(0), c.Byte(1), c.Int(2), c.Int(3) 131 + f, fmtVal, prec, bitSize := c.Float64(0), c.Value(1), c.Int(2), c.Int(3) 132 132 if c.Do() { 133 - c.Ret = FormatFloat(f, fmt, prec, bitSize) 133 + c.Ret, c.Err = FormatFloat(f, fmtVal, prec, bitSize) 134 134 } 135 135 }, 136 136 }, {
+45 -16
pkg/strconv/strconv.go
··· 21 21 package strconv 22 22 23 23 import ( 24 + "fmt" 25 + "math/big" 26 + "strconv" 27 + 28 + "cuelang.org/go/cue" 24 29 "cuelang.org/go/cue/literal" 25 30 "cuelang.org/go/internal" 26 - "math/big" 27 - "strconv" 28 31 ) 29 32 30 33 // ParseBool returns the boolean value represented by the string. ··· 222 225 // result assuming that the original was obtained from a floating-point 223 226 // value of bitSize bits (32 for float32, 64 for float64). 224 227 // 225 - // The format fmt is one of 226 - // 'b' (-ddddp±ddd, a binary exponent), 227 - // 'e' (-d.dddde±dd, a decimal exponent), 228 - // 'E' (-d.ddddE±dd, a decimal exponent), 229 - // 'f' (-ddd.dddd, no exponent), 230 - // 'g' ('e' for large exponents, 'f' otherwise), 231 - // 'G' ('E' for large exponents, 'f' otherwise), 232 - // 'x' (-0xd.ddddp±ddd, a hexadecimal fraction and binary exponent), or 233 - // 'X' (-0Xd.ddddP±ddd, a hexadecimal fraction and binary exponent). 228 + // The format fmt is a string or integer: one of 229 + // "b" (-ddddp±ddd, a binary exponent), 230 + // "e" (-d.dddde±dd, a decimal exponent), 231 + // "E" (-d.ddddE±dd, a decimal exponent), 232 + // "f" (-ddd.dddd, no exponent), 233 + // "g" ("e" for large exponents, "f" otherwise), 234 + // "G" ("E" for large exponents, "f" otherwise), 235 + // "x" (-0xd.ddddp±ddd, a hexadecimal fraction and binary exponent), or 236 + // "X" (-0Xd.ddddP±ddd, a hexadecimal fraction and binary exponent). 237 + // 238 + // For historical reasons, an integer (the ASCII code point of a 239 + // format character) is also accepted for the format. 234 240 // 235 241 // The precision prec controls the number of digits (excluding the exponent) 236 - // printed by the 'e', 'E', 'f', 'g', 'G', 'x', and 'X' formats. 237 - // For 'e', 'E', 'f', 'x', and 'X', it is the number of digits after the decimal point. 238 - // For 'g' and 'G' it is the maximum number of significant digits (trailing 242 + // printed by the "e", "E", "f", "g", "G", "x", and "X" formats. 243 + // For "e", "E", "f", "x", and "X", it is the number of digits after the decimal point. 244 + // For "g" and "G" it is the maximum number of significant digits (trailing 239 245 // zeros are removed). 240 246 // The special precision -1 uses the smallest number of digits 241 247 // necessary such that ParseFloat will return f exactly. 242 - func FormatFloat(f float64, fmt byte, prec, bitSize int) string { 243 - return strconv.FormatFloat(f, fmt, prec, bitSize) 248 + func FormatFloat(f float64, fmtVal cue.Value, prec, bitSize int) (string, error) { 249 + var fmtByte byte 250 + switch k := fmtVal.Kind(); k { 251 + case cue.StringKind: 252 + s, err := fmtVal.String() 253 + if err != nil { 254 + return "", err 255 + } 256 + if len(s) != 1 { 257 + return "", fmt.Errorf("expected single character string") 258 + } 259 + fmtByte = s[0] 260 + case cue.IntKind: 261 + n, err := fmtVal.Int64() 262 + if err != nil { 263 + return "", err 264 + } 265 + if n < 0 || n > 255 { 266 + return "", fmt.Errorf("format value %d out of range [0, 255]", n) 267 + } 268 + fmtByte = byte(n) 269 + default: 270 + return "", fmt.Errorf("unexpected kind %v", k) 271 + } 272 + return strconv.FormatFloat(f, fmtByte, prec, bitSize), nil 244 273 } 245 274 246 275 // FormatUint returns the string representation of i in the given base,
+92 -54
pkg/strconv/testdata/gen.txtar
··· 13 13 t8: strconv.FormatUint(170_141_183_460_469_231_731_687_303_715_884_105_728, 10) 14 14 t9: strconv.FormatUint(61, 62) 15 15 t10: strconv.FormatFloat(0.0, 102, -1, 64) 16 + // FormatFloat with string format argument 17 + t54: strconv.FormatFloat(3.14159, "g", -1, 64) 18 + t55: strconv.FormatFloat(3.14159, "f", 2, 64) 19 + t56: strconv.FormatFloat(3.14159, "e", 4, 64) 20 + t57: strconv.FormatFloat(3.14159, "E", 4, 64) 21 + // FormatFloat with integer format argument (103 == 'g') 22 + t58: strconv.FormatFloat(3.14159, 103, -1, 64) 16 23 // Test Atoi with large integers 17 24 t11: strconv.Atoi("2000000000000") 18 25 t12: strconv.Atoi("40000000000000000000") ··· 62 69 t53: strconv.ParseNumber("0xG") 63 70 -- out/strconv-v3 -- 64 71 Errors: 65 - t2: int 300 overflows byte in argument 1 in call to strconv.FormatFloat: 72 + t2: error in call to strconv.FormatFloat: format value 300 out of range [0, 255]: 66 73 ./in.cue:4:5 67 - t3: cannot use -1 (type int) as byte in argument 1 to strconv.FormatFloat: 74 + t3: error in call to strconv.FormatFloat: format value -1 out of range [0, 255]: 68 75 ./in.cue:5:5 69 - ./in.cue:5:31 70 - t4: cannot use 1.0 (type float) as int in argument 2 to strconv.FormatFloat: 71 - ./in.cue:6:31 76 + t4: error in call to strconv.FormatFloat: unexpected kind float: 77 + ./in.cue:6:5 72 78 t16: error in call to strconv.Atoi: strconv.Atoi: parsing "invalid": invalid syntax: 73 - ./in.cue:19:6 79 + ./in.cue:26:6 74 80 t18: error in call to strconv.ParseInt: strconv.ParseInt: parsing "128": value out of range: 75 - ./in.cue:22:6 81 + ./in.cue:29:6 76 82 t20: error in call to strconv.ParseInt: strconv.ParseInt: parsing "-129": value out of range: 77 - ./in.cue:24:6 83 + ./in.cue:31:6 78 84 t22: error in call to strconv.ParseInt: strconv.ParseInt: parsing "256": value out of range: 79 - ./in.cue:26:6 85 + ./in.cue:33:6 80 86 t25: error in call to strconv.ParseInt: strconv.ParseInt: parsing "7": value out of range: 81 - ./in.cue:29:6 87 + ./in.cue:36:6 82 88 t26: error in call to strconv.ParseInt: strconv.ParseInt: parsing "4": value out of range: 83 - ./in.cue:30:6 89 + ./in.cue:37:6 84 90 t28: error in call to strconv.ParseInt: strconv.ParseInt: parsing "-5": value out of range: 85 - ./in.cue:32:6 91 + ./in.cue:39:6 86 92 t30: error in call to strconv.ParseInt: strconv.ParseInt: parsing "FF": value out of range: 87 - ./in.cue:34:6 93 + ./in.cue:41:6 88 94 t31: error in call to strconv.ParseInt: strconv.ParseInt: parsing "100": value out of range: 89 - ./in.cue:35:6 95 + ./in.cue:42:6 90 96 t32: error in call to strconv.ParseInt: strconv.ParseInt: parsing "invalid": invalid syntax: 91 - ./in.cue:36:6 97 + ./in.cue:43:6 92 98 t33: error in call to strconv.ParseInt: strconv.ParseInt: parsing "123": value out of range: 93 - ./in.cue:37:6 99 + ./in.cue:44:6 94 100 t35: error in call to strconv.ParseUint: strconv.ParseUint: parsing "256": value out of range: 95 - ./in.cue:40:6 101 + ./in.cue:47:6 96 102 t38: error in call to strconv.ParseUint: strconv.ParseUint: parsing "512": value out of range: 97 - ./in.cue:43:6 103 + ./in.cue:50:6 98 104 t42: error in call to strconv.ParseUint: strconv.ParseUint: parsing "8": value out of range: 99 - ./in.cue:47:6 105 + ./in.cue:54:6 100 106 t44: error in call to strconv.ParseUint: strconv.ParseUint: parsing "100": value out of range: 101 - ./in.cue:49:6 107 + ./in.cue:56:6 102 108 t45: error in call to strconv.ParseUint: strconv.ParseUint: parsing "invalid": invalid syntax: 103 - ./in.cue:50:6 109 + ./in.cue:57:6 104 110 t46: error in call to strconv.ParseUint: strconv.ParseUint: parsing "123": value out of range: 105 - ./in.cue:51:6 111 + ./in.cue:58:6 106 112 t47: error in call to strconv.ParseUint: strconv.ParseUint: parsing "-1": value out of range: 107 - ./in.cue:52:6 113 + ./in.cue:59:6 108 114 t52: error in call to strconv.ParseNumber: strconv.ParseNumber: parsing "1_": illegal '_' in number: 109 - ./in.cue:58:6 115 + ./in.cue:65:6 110 116 t53: error in call to strconv.ParseNumber: strconv.ParseNumber: parsing "0xG": illegal hexadecimal number "0xG": 111 - ./in.cue:59:6 117 + ./in.cue:66:6 112 118 113 119 Result: 114 120 t1: "40" 115 - t2: _|_ // t2: int 300 overflows byte in argument 1 in call to strconv.FormatFloat 116 - t3: _|_ // t3: cannot use -1 (type int) as byte in argument 1 to strconv.FormatFloat 117 - t4: _|_ // t4: cannot use 1.0 (type float) as int in argument 2 to strconv.FormatFloat 121 + t2: _|_ // t2: error in call to strconv.FormatFloat: format value 300 out of range [0, 255] 122 + t3: _|_ // t3: error in call to strconv.FormatFloat: format value -1 out of range [0, 255] 123 + t4: _|_ // t4: error in call to strconv.FormatFloat: unexpected kind float 118 124 t5: "true" 119 125 t6: "170141183460469231731687303715884105728" 120 126 t7: "40" 121 127 t8: "170141183460469231731687303715884105728" 122 128 t9: "Z" 123 129 t10: "0" 130 + // FormatFloat with string format argument 131 + t54: "3.14159" 132 + t55: "3.14" 133 + t56: "3.1416e+00" 134 + t57: "3.1416E+00" 135 + // FormatFloat with integer format argument (103 == 'g') 136 + t58: "3.14159" 124 137 // Test Atoi with large integers 125 138 t11: 2000000000000 126 139 t12: 40000000000000000000 ··· 172 185 diff old new 173 186 --- old 174 187 +++ new 175 - @@ -6,8 +6,46 @@ 176 - ./in.cue:5:31 177 - t4: cannot use 1.0 (type float) as int in argument 2 to strconv.FormatFloat: 178 - ./in.cue:6:31 188 + @@ -1,19 +1,56 @@ 189 + Errors: 190 + -t2: int 300 overflows byte in argument 1 in call to strconv.FormatFloat: 191 + +t2: error in call to strconv.FormatFloat: format value 300 out of range [0, 255]: 192 + ./in.cue:4:5 193 + -t3: cannot use -1 (type int) as byte in argument 1 to strconv.FormatFloat: 194 + +t3: error in call to strconv.FormatFloat: format value -1 out of range [0, 255]: 195 + ./in.cue:5:5 196 + - ./in.cue:5:31 197 + -t4: cannot use 1.0 (type float) as int in argument 2 to strconv.FormatFloat: 198 + - ./in.cue:6:31 179 199 -t16: strconv.Atoi: parsing "invalid": invalid syntax: 180 200 - ./in.cue:22:5 201 + +t4: error in call to strconv.FormatFloat: unexpected kind float: 202 + + ./in.cue:6:5 181 203 +t16: error in call to strconv.Atoi: strconv.Atoi: parsing "invalid": invalid syntax: 182 - + ./in.cue:19:6 204 + + ./in.cue:26:6 183 205 +t18: error in call to strconv.ParseInt: strconv.ParseInt: parsing "128": value out of range: 184 - + ./in.cue:22:6 206 + + ./in.cue:29:6 185 207 +t20: error in call to strconv.ParseInt: strconv.ParseInt: parsing "-129": value out of range: 186 - + ./in.cue:24:6 208 + + ./in.cue:31:6 187 209 +t22: error in call to strconv.ParseInt: strconv.ParseInt: parsing "256": value out of range: 188 - + ./in.cue:26:6 210 + + ./in.cue:33:6 189 211 +t25: error in call to strconv.ParseInt: strconv.ParseInt: parsing "7": value out of range: 190 - + ./in.cue:29:6 212 + + ./in.cue:36:6 191 213 +t26: error in call to strconv.ParseInt: strconv.ParseInt: parsing "4": value out of range: 192 - + ./in.cue:30:6 214 + + ./in.cue:37:6 193 215 +t28: error in call to strconv.ParseInt: strconv.ParseInt: parsing "-5": value out of range: 194 - + ./in.cue:32:6 216 + + ./in.cue:39:6 195 217 +t30: error in call to strconv.ParseInt: strconv.ParseInt: parsing "FF": value out of range: 196 - + ./in.cue:34:6 218 + + ./in.cue:41:6 197 219 +t31: error in call to strconv.ParseInt: strconv.ParseInt: parsing "100": value out of range: 198 - + ./in.cue:35:6 220 + + ./in.cue:42:6 199 221 +t32: error in call to strconv.ParseInt: strconv.ParseInt: parsing "invalid": invalid syntax: 200 - + ./in.cue:36:6 222 + + ./in.cue:43:6 201 223 +t33: error in call to strconv.ParseInt: strconv.ParseInt: parsing "123": value out of range: 202 - + ./in.cue:37:6 224 + + ./in.cue:44:6 203 225 +t35: error in call to strconv.ParseUint: strconv.ParseUint: parsing "256": value out of range: 204 - + ./in.cue:40:6 226 + + ./in.cue:47:6 205 227 +t38: error in call to strconv.ParseUint: strconv.ParseUint: parsing "512": value out of range: 206 - + ./in.cue:43:6 228 + + ./in.cue:50:6 207 229 +t42: error in call to strconv.ParseUint: strconv.ParseUint: parsing "8": value out of range: 208 - + ./in.cue:47:6 230 + + ./in.cue:54:6 209 231 +t44: error in call to strconv.ParseUint: strconv.ParseUint: parsing "100": value out of range: 210 - + ./in.cue:49:6 232 + + ./in.cue:56:6 211 233 +t45: error in call to strconv.ParseUint: strconv.ParseUint: parsing "invalid": invalid syntax: 212 - + ./in.cue:50:6 234 + + ./in.cue:57:6 213 235 +t46: error in call to strconv.ParseUint: strconv.ParseUint: parsing "123": value out of range: 214 - + ./in.cue:51:6 236 + + ./in.cue:58:6 215 237 +t47: error in call to strconv.ParseUint: strconv.ParseUint: parsing "-1": value out of range: 216 - + ./in.cue:52:6 238 + + ./in.cue:59:6 217 239 +t52: error in call to strconv.ParseNumber: strconv.ParseNumber: parsing "1_": illegal '_' in number: 218 - + ./in.cue:58:6 240 + + ./in.cue:65:6 219 241 +t53: error in call to strconv.ParseNumber: strconv.ParseNumber: parsing "0xG": illegal hexadecimal number "0xG": 220 - + ./in.cue:59:6 242 + + ./in.cue:66:6 221 243 222 244 Result: 223 245 t1: "40" 224 - @@ -20,12 +58,31 @@ 246 + -t2: _|_ // t2: int 300 overflows byte in argument 1 in call to strconv.FormatFloat 247 + -t3: _|_ // t3: cannot use -1 (type int) as byte in argument 1 to strconv.FormatFloat 248 + -t4: _|_ // t4: cannot use 1.0 (type float) as int in argument 2 to strconv.FormatFloat 249 + +t2: _|_ // t2: error in call to strconv.FormatFloat: format value 300 out of range [0, 255] 250 + +t3: _|_ // t3: error in call to strconv.FormatFloat: format value -1 out of range [0, 255] 251 + +t4: _|_ // t4: error in call to strconv.FormatFloat: unexpected kind float 252 + t5: "true" 253 + t6: "170141183460469231731687303715884105728" 254 + t7: "40" 255 + @@ -20,12 +57,38 @@ 225 256 t8: "170141183460469231731687303715884105728" 226 257 t9: "Z" 227 258 t10: "0" 259 + +// FormatFloat with string format argument 260 + +t54: "3.14159" 261 + +t55: "3.14" 262 + +t56: "3.1416e+00" 263 + +t57: "3.1416E+00" 264 + +// FormatFloat with integer format argument (103 == 'g') 265 + +t58: "3.14159" 228 266 +// Test Atoi with large integers 229 267 t11: 2000000000000 230 268 t12: 40000000000000000000 ··· 254 292 // Test ParseUint with various bit widths 255 293 t34: 255 256 294 t35: _|_ // t35: error in call to strconv.ParseUint: strconv.ParseUint: parsing "256": value out of range 257 - @@ -41,3 +98,10 @@ 295 + @@ -41,3 +104,10 @@ 258 296 t45: _|_ // t45: error in call to strconv.ParseUint: strconv.ParseUint: parsing "invalid": invalid syntax 259 297 t46: _|_ // t46: error in call to strconv.ParseUint: strconv.ParseUint: parsing "123": value out of range 260 298 t47: _|_ // t47: error in call to strconv.ParseUint: strconv.ParseUint: parsing "-1": value out of range