Skip to content

Commit aec0116

Browse files
cjorge-graphopsmvdan
authored andcommitted
pkg/strconv: add ParseNumber builtin
Expose literal.ParseNum via pkg/strconv so CUE code can parse native number literals through the standard library. The wrapper returns an internal.Decimal and surfaces syntax issues as *strconv.NumError, matching the existing ParseInt/ParseFloat helpers. The main use case here is being able to parse CUE number strings such as 1Ki, which are not accepted by strconv.ParseInt. Moreover, this API accepts both integer and floating point numbers, so it's a superset of both strconv's ParseInt and ParseFloat. We choose to name the built-in ParseNumber rather than ParseNum given that this directly reflects the "number" predeclared identifier in the CUE spec, so it's best to not shorten that name. Closes #4139 as merged as of commit ac7daa6. Signed-off-by: Carlos Jorge <[email protected]> Change-Id: I1ed97630a24300884588bfdda0130fe40a7e7e2b Reviewed-on: https://cue.gerrithub.io/c/cue-lang/cue/+/1226125 Reviewed-by: Marcel van Lohuizen <[email protected]> Unity-Result: CUE porcuepine <[email protected]> TryBot-Result: CUEcueckoo <[email protected]>
1 parent 5e7258e commit aec0116

File tree

3 files changed

+62
-0
lines changed

3 files changed

+62
-0
lines changed

pkg/strconv/pkg.go

Lines changed: 12 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pkg/strconv/strconv.go

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121
package strconv
2222

2323
import (
24+
"cuelang.org/go/cue/literal"
25+
"cuelang.org/go/internal"
2426
"math/big"
2527
"strconv"
2628
)
@@ -65,6 +67,36 @@ func ParseFloat(s string, bitSize int) (float64, error) {
6567
return strconv.ParseFloat(s, bitSize)
6668
}
6769

70+
// ParseNumber interprets s using the full CUE number literal syntax and returns
71+
// the resulting value as an arbitrary-precision decimal. It accepts decimal
72+
// and non-decimal bases, underscores as separators, fractional syntax, and
73+
// the decimal or binary multiplier suffixes defined by CUE (for example "1Ki"
74+
// and "10M").
75+
//
76+
// If s is not syntactically well-formed, ParseNumber returns a *strconv.NumError
77+
// with Err containing detailed syntax information. Semantic errors, such as a
78+
// multiplier that cannot be represented, are reported in the same way.
79+
func ParseNumber(s string) (*internal.Decimal, error) {
80+
var info literal.NumInfo
81+
if err := literal.ParseNum(s, &info); err != nil {
82+
return nil, &strconv.NumError{
83+
Func: "ParseNumber",
84+
Num: s,
85+
Err: err,
86+
}
87+
}
88+
89+
var dec internal.Decimal
90+
if err := info.Decimal(&dec); err != nil {
91+
return nil, &strconv.NumError{
92+
Func: "ParseNumber",
93+
Num: s,
94+
Err: err,
95+
}
96+
}
97+
return &dec, nil
98+
}
99+
68100
// IntSize is the size in bits of an int or uint value.
69101
const IntSize = 64
70102

pkg/strconv/testdata/gen.txtar

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,13 @@ t44: strconv.ParseUint("100", 16, 8) // hex overflow uint8
5353
t45: strconv.ParseUint("invalid", 10, 8) // syntax error
5454
t46: strconv.ParseUint("123", 10, -1) // negative bitSize error
5555
t47: strconv.ParseUint("-1", 10, 8) // negative value error
56+
// Test ParseNumber
57+
t48: strconv.ParseNumber("123.456")
58+
t49: strconv.ParseNumber("0xFF")
59+
t50: strconv.ParseNumber("1Ki")
60+
t51: strconv.ParseNumber("-.5")
61+
t52: strconv.ParseNumber("1_")
62+
t53: strconv.ParseNumber("0xG")
5663
-- out/strconv-v3 --
5764
Errors:
5865
t2: int 300 overflows byte in argument 1 in call to strconv.FormatFloat:
@@ -98,6 +105,10 @@ t46: error in call to strconv.ParseUint: strconv.ParseUint: parsing "123": value
98105
./in.cue:51:6
99106
t47: error in call to strconv.ParseUint: strconv.ParseUint: parsing "-1": value out of range:
100107
./in.cue:52:6
108+
t52: error in call to strconv.ParseNumber: strconv.ParseNumber: parsing "1_": illegal '_' in number:
109+
./in.cue:58:6
110+
t53: error in call to strconv.ParseNumber: strconv.ParseNumber: parsing "0xG": illegal hexadecimal number "0xG":
111+
./in.cue:59:6
101112

102113
Result:
103114
t1: "40"
@@ -150,6 +161,13 @@ t44: _|_ // t44: error in call to strconv.ParseUint: strconv.ParseUint: parsing
150161
t45: _|_ // t45: error in call to strconv.ParseUint: strconv.ParseUint: parsing "invalid": invalid syntax
151162
t46: _|_ // t46: error in call to strconv.ParseUint: strconv.ParseUint: parsing "123": value out of range
152163
t47: _|_ // t47: error in call to strconv.ParseUint: strconv.ParseUint: parsing "-1": value out of range
164+
// Test ParseNumber
165+
t48: 123.456
166+
t49: 255
167+
t50: 1024
168+
t51: -0.5
169+
t52: _|_ // t52: error in call to strconv.ParseNumber: strconv.ParseNumber: parsing "1_": illegal '_' in number
170+
t53: _|_ // t53: error in call to strconv.ParseNumber: strconv.ParseNumber: parsing "0xG": illegal hexadecimal number "0xG"
153171
-- diff/-out/strconv-v3<==>+out/strconv --
154172
diff old new
155173
--- old

0 commit comments

Comments
 (0)