strconv: change atof64 to return an error, if the parsed value is not a valid number (#13424)
parent
1c19573382
commit
7f29418c63
|
@ -511,12 +511,12 @@ pub fn (s string) i16() i16 {
|
||||||
|
|
||||||
// f32 returns the value of the string as f32 `'1.0'.f32() == f32(1)`.
|
// f32 returns the value of the string as f32 `'1.0'.f32() == f32(1)`.
|
||||||
pub fn (s string) f32() f32 {
|
pub fn (s string) f32() f32 {
|
||||||
return f32(strconv.atof64(s))
|
return f32(strconv.atof64(s) or { 0 })
|
||||||
}
|
}
|
||||||
|
|
||||||
// f64 returns the value of the string as f64 `'1.0'.f64() == f64(1)`.
|
// f64 returns the value of the string as f64 `'1.0'.f64() == f64(1)`.
|
||||||
pub fn (s string) f64() f64 {
|
pub fn (s string) f64() f64 {
|
||||||
return strconv.atof64(s)
|
return strconv.atof64(s) or { 0 }
|
||||||
}
|
}
|
||||||
|
|
||||||
// u8 returns the value of the string as u8 `'1'.u8() == u8(1)`.
|
// u8 returns the value of the string as u8 `'1'.u8() == u8(1)`.
|
||||||
|
|
|
@ -104,6 +104,7 @@ pub const (
|
||||||
parser_mzero = 2 // number is negative, module smaller
|
parser_mzero = 2 // number is negative, module smaller
|
||||||
parser_pinf = 3 // number is higher than +HUGE_VAL
|
parser_pinf = 3 // number is higher than +HUGE_VAL
|
||||||
parser_minf = 4 // number is lower than -HUGE_VAL
|
parser_minf = 4 // number is lower than -HUGE_VAL
|
||||||
|
parser_invalid_number = 5 // invalid number, used for '#@%^' for example
|
||||||
//
|
//
|
||||||
// char constants
|
// char constants
|
||||||
// Note: Modify these if working with non-ASCII encoding
|
// Note: Modify these if working with non-ASCII encoding
|
||||||
|
@ -232,6 +233,9 @@ fn parser(s string) (int, PrepNumber) {
|
||||||
result = strconv.parser_pzero
|
result = strconv.parser_pzero
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if i == 0 && s.len > 0 {
|
||||||
|
return strconv.parser_invalid_number, pn
|
||||||
|
}
|
||||||
return result, pn
|
return result, pn
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -403,9 +407,9 @@ fn converter(mut pn PrepNumber) u64 {
|
||||||
// Public functions
|
// Public functions
|
||||||
|
|
||||||
// atof64 return a f64 from a string doing a parsing operation
|
// atof64 return a f64 from a string doing a parsing operation
|
||||||
pub fn atof64(s string) f64 {
|
pub fn atof64(s string) ?f64 {
|
||||||
if s.len == 0 {
|
if s.len == 0 {
|
||||||
return 0
|
return error('expected a number found an empty string')
|
||||||
}
|
}
|
||||||
mut pn := PrepNumber{}
|
mut pn := PrepNumber{}
|
||||||
mut res_parsing := 0
|
mut res_parsing := 0
|
||||||
|
@ -428,7 +432,9 @@ pub fn atof64(s string) f64 {
|
||||||
strconv.parser_minf {
|
strconv.parser_minf {
|
||||||
res.u = strconv.double_minus_infinity
|
res.u = strconv.double_minus_infinity
|
||||||
}
|
}
|
||||||
else {}
|
else {
|
||||||
|
return error('not a number')
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return unsafe { res.f }
|
return unsafe { res.f }
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,10 @@
|
||||||
module strconv
|
module strconv
|
||||||
|
|
||||||
// atof64 return a f64 from a string doing a parsing operation
|
// atof64 return a f64 from a string doing a parsing operation
|
||||||
pub fn atof64(s string) f64 {
|
pub fn atof64(s string) ?f64 {
|
||||||
|
// TODO: handle parsing invalid numbers as close as possible to the pure V version
|
||||||
|
// that may be slower, but more portable, and will guarantee that higher level code
|
||||||
|
// works the same in the JS version, as well as in the C and Native versions.
|
||||||
res := 0.0
|
res := 0.0
|
||||||
#res.val = Number(s.str)
|
#res.val = Number(s.str)
|
||||||
|
|
||||||
|
|
|
@ -36,7 +36,8 @@ fn test_atof() {
|
||||||
// check conversion case 1 string <=> string
|
// check conversion case 1 string <=> string
|
||||||
for c, x in src_num {
|
for c, x in src_num {
|
||||||
// slow atof
|
// slow atof
|
||||||
assert strconv.atof64(src_num_str[c]).strlong() == x.strlong()
|
val := strconv.atof64(src_num_str[c]) or { panic(err) }
|
||||||
|
assert val.strlong() == x.strlong()
|
||||||
|
|
||||||
// quick atof
|
// quick atof
|
||||||
mut s1 := (strconv.atof_quick(src_num_str[c]).str())
|
mut s1 := (strconv.atof_quick(src_num_str[c]).str())
|
||||||
|
@ -56,7 +57,8 @@ fn test_atof() {
|
||||||
// we don't test atof_quick beacuse we already know the rounding error
|
// we don't test atof_quick beacuse we already know the rounding error
|
||||||
for c, x in src_num_str {
|
for c, x in src_num_str {
|
||||||
b := src_num[c].strlong()
|
b := src_num[c].strlong()
|
||||||
a1 := strconv.atof64(x).strlong()
|
value := strconv.atof64(x) or { panic(err) }
|
||||||
|
a1 := value.strlong()
|
||||||
assert a1 == b
|
assert a1 == b
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -73,3 +75,18 @@ fn test_atof() {
|
||||||
assert *ptr == u64(0x8000000000000000)
|
assert *ptr == u64(0x8000000000000000)
|
||||||
println('DONE!')
|
println('DONE!')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn test_atof_errors() {
|
||||||
|
if x := strconv.atof64('') {
|
||||||
|
eprintln('> x: $x')
|
||||||
|
assert false // strconv.atof64 should have failed
|
||||||
|
} else {
|
||||||
|
assert err.str() == 'expected a number found an empty string'
|
||||||
|
}
|
||||||
|
if x := strconv.atof64('####') {
|
||||||
|
eprintln('> x: $x')
|
||||||
|
assert false // strconv.atof64 should have failed
|
||||||
|
} else {
|
||||||
|
assert err.str() == 'not a number'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -191,7 +191,7 @@ pub fn (mut e Eval) expr(expr ast.Expr, expecting ast.Type) Object {
|
||||||
}) // TODO: numbers larger than 2^63 (for u64)
|
}) // TODO: numbers larger than 2^63 (for u64)
|
||||||
}
|
}
|
||||||
ast.FloatLiteral {
|
ast.FloatLiteral {
|
||||||
return f64(strconv.atof64(expr.val))
|
return f64(strconv.atof64(expr.val) or { e.error(err.str()) })
|
||||||
}
|
}
|
||||||
ast.BoolLiteral {
|
ast.BoolLiteral {
|
||||||
return expr.val
|
return expr.val
|
||||||
|
|
Loading…
Reference in New Issue