mirror of
https://github.com/odin-lang/Odin.git
synced 2026-06-09 11:58:10 +00:00
Merge pull request #3675 from Feoramund/fix-partial-infinity
Fix partial parsing of `infinity`
This commit is contained in:
@@ -882,13 +882,16 @@ parse_f64_prefix :: proc(str: string) -> (value: f64, nr: int, ok: bool) {
|
||||
s = s[1:]
|
||||
fallthrough
|
||||
case 'i', 'I':
|
||||
n = common_prefix_len_ignore_case(s, "infinity")
|
||||
if 3 < n && n < 8 { // "inf" or "infinity"
|
||||
n = 3
|
||||
}
|
||||
if n == 3 || n == 8 {
|
||||
m := common_prefix_len_ignore_case(s, "infinity")
|
||||
if 3 <= m && m < 9 { // "inf" to "infinity"
|
||||
f = 0h7ff00000_00000000 if sign == 1 else 0hfff00000_00000000
|
||||
n = nsign + 3
|
||||
if m == 8 {
|
||||
// We only count the entire prefix if it is precisely "infinity".
|
||||
n = nsign + m
|
||||
} else {
|
||||
// The string was either only "inf" or incomplete.
|
||||
n = nsign + 3
|
||||
}
|
||||
ok = true
|
||||
return
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ all_bsd: download_test_assets \
|
||||
reflect_test \
|
||||
runtime_test \
|
||||
slice_test \
|
||||
strconv_test \
|
||||
strings_test \
|
||||
thread_test \
|
||||
time_test
|
||||
@@ -98,6 +99,9 @@ runtime_test:
|
||||
slice_test:
|
||||
$(ODIN) test slice $(COMMON) -out:test_core_slice
|
||||
|
||||
strconv_test:
|
||||
$(ODIN) test strconv $(COMMON) -out:test_core_strconv
|
||||
|
||||
strings_test:
|
||||
$(ODIN) test strings $(COMMON) -out:test_core_strings
|
||||
|
||||
|
||||
@@ -103,6 +103,11 @@ echo Running core:slice tests
|
||||
echo ---
|
||||
%PATH_TO_ODIN% test slice %COMMON% -out:test_core_slice.exe || exit /b
|
||||
|
||||
echo ---
|
||||
echo Running core:strconv tests
|
||||
echo ---
|
||||
%PATH_TO_ODIN% test strconv %COMMON% -out:test_core_strconv.exe || exit /b
|
||||
|
||||
echo ---
|
||||
echo Running core:strings tests
|
||||
echo ---
|
||||
|
||||
145
tests/core/strconv/test_core_strconv.odin
Normal file
145
tests/core/strconv/test_core_strconv.odin
Normal file
@@ -0,0 +1,145 @@
|
||||
package test_core_strconv
|
||||
|
||||
import "core:math"
|
||||
import "core:strconv"
|
||||
import "core:testing"
|
||||
|
||||
@(test)
|
||||
test_float :: proc(t: ^testing.T) {
|
||||
n: int
|
||||
f: f64
|
||||
ok: bool
|
||||
|
||||
f, ok = strconv.parse_f64("1.2", &n)
|
||||
testing.expect_value(t, f, 1.2)
|
||||
testing.expect_value(t, n, 3)
|
||||
testing.expect_value(t, ok, true)
|
||||
|
||||
f, ok = strconv.parse_f64("1.2a", &n)
|
||||
testing.expect_value(t, f, 1.2)
|
||||
testing.expect_value(t, n, 3)
|
||||
testing.expect_value(t, ok, false)
|
||||
|
||||
f, ok = strconv.parse_f64("+", &n)
|
||||
testing.expect_value(t, f, 0)
|
||||
testing.expect_value(t, n, 0)
|
||||
testing.expect_value(t, ok, false)
|
||||
|
||||
f, ok = strconv.parse_f64("-", &n)
|
||||
testing.expect_value(t, f, 0)
|
||||
testing.expect_value(t, n, 0)
|
||||
testing.expect_value(t, ok, false)
|
||||
|
||||
}
|
||||
|
||||
@(test)
|
||||
test_nan :: proc(t: ^testing.T) {
|
||||
n: int
|
||||
f: f64
|
||||
ok: bool
|
||||
|
||||
f, ok = strconv.parse_f64("nan", &n)
|
||||
testing.expect_value(t, math.classify(f), math.Float_Class.NaN)
|
||||
testing.expect_value(t, n, 3)
|
||||
testing.expect_value(t, ok, true)
|
||||
|
||||
f, ok = strconv.parse_f64("nAN", &n)
|
||||
testing.expect_value(t, math.classify(f), math.Float_Class.NaN)
|
||||
testing.expect_value(t, n, 3)
|
||||
testing.expect_value(t, ok, true)
|
||||
|
||||
f, ok = strconv.parse_f64("Nani", &n)
|
||||
testing.expect_value(t, math.classify(f), math.Float_Class.NaN)
|
||||
testing.expect_value(t, n, 3)
|
||||
testing.expect_value(t, ok, false)
|
||||
}
|
||||
|
||||
@(test)
|
||||
test_infinity :: proc(t: ^testing.T) {
|
||||
pos_inf := math.inf_f64(+1)
|
||||
neg_inf := math.inf_f64(-1)
|
||||
|
||||
n: int
|
||||
s := "infinity"
|
||||
|
||||
for i in 0 ..< len(s) + 1 {
|
||||
ss := s[:i]
|
||||
f, ok := strconv.parse_f64(ss, &n)
|
||||
if i >= 3 { // "inf" .. "infinity"
|
||||
expected_n := 8 if i == 8 else 3
|
||||
expected_ok := i == 3 || i == 8
|
||||
testing.expect_value(t, f, pos_inf)
|
||||
testing.expect_value(t, n, expected_n)
|
||||
testing.expect_value(t, ok, expected_ok)
|
||||
testing.expect_value(t, math.classify(f), math.Float_Class.Inf)
|
||||
} else { // invalid substring
|
||||
testing.expect_value(t, f, 0)
|
||||
testing.expect_value(t, n, 0)
|
||||
testing.expect_value(t, ok, false)
|
||||
testing.expect_value(t, math.classify(f), math.Float_Class.Zero)
|
||||
}
|
||||
}
|
||||
|
||||
s = "+infinity"
|
||||
for i in 0 ..< len(s) + 1 {
|
||||
ss := s[:i]
|
||||
f, ok := strconv.parse_f64(ss, &n)
|
||||
if i >= 4 { // "+inf" .. "+infinity"
|
||||
expected_n := 9 if i == 9 else 4
|
||||
expected_ok := i == 4 || i == 9
|
||||
testing.expect_value(t, f, pos_inf)
|
||||
testing.expect_value(t, n, expected_n)
|
||||
testing.expect_value(t, ok, expected_ok)
|
||||
testing.expect_value(t, math.classify(f), math.Float_Class.Inf)
|
||||
} else { // invalid substring
|
||||
testing.expect_value(t, f, 0)
|
||||
testing.expect_value(t, n, 0)
|
||||
testing.expect_value(t, ok, false)
|
||||
testing.expect_value(t, math.classify(f), math.Float_Class.Zero)
|
||||
}
|
||||
}
|
||||
|
||||
s = "-infinity"
|
||||
for i in 0 ..< len(s) + 1 {
|
||||
ss := s[:i]
|
||||
f, ok := strconv.parse_f64(ss, &n)
|
||||
if i >= 4 { // "-inf" .. "infinity"
|
||||
expected_n := 9 if i == 9 else 4
|
||||
expected_ok := i == 4 || i == 9
|
||||
testing.expect_value(t, f, neg_inf)
|
||||
testing.expect_value(t, n, expected_n)
|
||||
testing.expect_value(t, ok, expected_ok)
|
||||
testing.expect_value(t, math.classify(f), math.Float_Class.Neg_Inf)
|
||||
} else { // invalid substring
|
||||
testing.expect_value(t, f, 0)
|
||||
testing.expect_value(t, n, 0)
|
||||
testing.expect_value(t, ok, false)
|
||||
testing.expect_value(t, math.classify(f), math.Float_Class.Zero)
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure odd casing works.
|
||||
batch := [?]string {"INFiniTY", "iNfInItY", "InFiNiTy"}
|
||||
for ss in batch {
|
||||
f, ok := strconv.parse_f64(ss, &n)
|
||||
testing.expect_value(t, f, pos_inf)
|
||||
testing.expect_value(t, n, 8)
|
||||
testing.expect_value(t, ok, true)
|
||||
testing.expect_value(t, math.classify(f), math.Float_Class.Inf)
|
||||
}
|
||||
|
||||
// Explicitly check how trailing characters are handled.
|
||||
s = "infinityyyy"
|
||||
f, ok := strconv.parse_f64(s, &n)
|
||||
testing.expect_value(t, f, pos_inf)
|
||||
testing.expect_value(t, n, 8)
|
||||
testing.expect_value(t, ok, false)
|
||||
testing.expect_value(t, math.classify(f), math.Float_Class.Inf)
|
||||
|
||||
s = "inflippity"
|
||||
f, ok = strconv.parse_f64(s, &n)
|
||||
testing.expect_value(t, f, pos_inf)
|
||||
testing.expect_value(t, n, 3)
|
||||
testing.expect_value(t, ok, false)
|
||||
testing.expect_value(t, math.classify(f), math.Float_Class.Inf)
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
// Tests issue #2087 https://github.com/odin-lang/Odin/issues/2087
|
||||
package test_issues
|
||||
|
||||
import "core:math"
|
||||
import "core:strconv"
|
||||
import "core:testing"
|
||||
|
||||
@(test)
|
||||
test_parse_float :: proc(t: ^testing.T) {
|
||||
{
|
||||
f, ok := strconv.parse_f64("1.2")
|
||||
testing.expect(t, ok && f == 1.2, "expected f64(1.2), fully consumed")
|
||||
f, ok = strconv.parse_f64("1.2a")
|
||||
testing.expect(t, !ok && f == 1.2, "expected f64(1.2), partially consumed")
|
||||
f, ok = strconv.parse_f64("+")
|
||||
testing.expect(t, !ok && f == 0.0, "expected f64(0.0), with ok=false")
|
||||
f, ok = strconv.parse_f64("-")
|
||||
testing.expect(t, !ok && f == 0.0, "expected f64(0.0), with ok=false")
|
||||
|
||||
|
||||
f, ok = strconv.parse_f64("inf")
|
||||
testing.expect(t, ok && math.classify(f) == math.Float_Class.Inf, "expected f64(+inf), fully consumed")
|
||||
f, ok = strconv.parse_f64("+inf")
|
||||
testing.expect(t, ok && math.classify(f) == math.Float_Class.Inf, "expected f64(+inf), fully consumed")
|
||||
f, ok = strconv.parse_f64("-inf")
|
||||
testing.expect(t, ok && math.classify(f) == math.Float_Class.Neg_Inf, "expected f64(-inf), fully consumed")
|
||||
f, ok = strconv.parse_f64("inFinity")
|
||||
testing.expect(t, !ok && math.classify(f) == math.Float_Class.Inf, "expected f64(+inf), partially consumed")
|
||||
f, ok = strconv.parse_f64("+InFinity")
|
||||
testing.expect(t, !ok && math.classify(f) == math.Float_Class.Inf, "expected f64(+inf), partially consumed")
|
||||
f, ok = strconv.parse_f64("-InfiniTy")
|
||||
testing.expect(t, !ok && math.classify(f) == math.Float_Class.Neg_Inf, "expected f64(-inf), partially consumed")
|
||||
f, ok = strconv.parse_f64("nan")
|
||||
testing.expect(t, ok && math.classify(f) == math.Float_Class.NaN, "expected f64(nan), fully consumed")
|
||||
f, ok = strconv.parse_f64("nAN")
|
||||
testing.expect(t, ok && math.classify(f) == math.Float_Class.NaN, "expected f64(nan), fully consumed")
|
||||
}
|
||||
{
|
||||
f, ok := strconv.parse_f32("1.2")
|
||||
testing.expect(t, ok && f == 1.2, "expected f32(1.2), fully consumed")
|
||||
|
||||
f, ok = strconv.parse_f32("1.2a")
|
||||
testing.expect(t, !ok && f == 1.2, "expected f32(1.2), partially consumed")
|
||||
|
||||
f, ok = strconv.parse_f32("inf")
|
||||
testing.expect(t, ok && math.classify(f) == math.Float_Class.Inf, "expected f32(+inf), fully consumed")
|
||||
f, ok = strconv.parse_f32("+inf")
|
||||
testing.expect(t, ok && math.classify(f) == math.Float_Class.Inf, "expected f32(+inf), fully consumed")
|
||||
f, ok = strconv.parse_f32("-inf")
|
||||
testing.expect(t, ok && math.classify(f) == math.Float_Class.Neg_Inf, "expected f32(-inf), fully consumed")
|
||||
f, ok = strconv.parse_f32("inFinity")
|
||||
testing.expect(t, !ok && math.classify(f) == math.Float_Class.Inf, "expected f32(+inf), partially consumed")
|
||||
f, ok = strconv.parse_f32("+InFinity")
|
||||
testing.expect(t, !ok && math.classify(f) == math.Float_Class.Inf, "expected f32(+inf), partially consumed")
|
||||
f, ok = strconv.parse_f32("-InfiniTy")
|
||||
testing.expect(t, !ok && math.classify(f) == math.Float_Class.Neg_Inf, "expected f32(-inf), partially consumed")
|
||||
f, ok = strconv.parse_f32("nan")
|
||||
testing.expect(t, ok && math.classify(f) == math.Float_Class.NaN, "expected f32(nan), fully consumed")
|
||||
f, ok = strconv.parse_f32("nAN")
|
||||
testing.expect(t, ok && math.classify(f) == math.Float_Class.NaN, "expected f32(nan), fully consumed")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user