Browse Source

Merge pull request #2092 from Kelimion/strconv

[strconv] Add parsing of Inf & NaN
Jeroen van Rijn 2 years ago
parent
commit
1162e30768

+ 33 - 1
core/strconv/strconv.odin

@@ -567,7 +567,7 @@ parse_f32 :: proc(s: string, n: ^int = nil) -> (value: f32, ok: bool) {
 // ```
 parse_f64 :: proc(str: string, n: ^int = nil) -> (value: f64, ok: bool) {
 	s := str
-	defer if n != nil { n^ = len(str)-len(s) }
+	defer if n != nil { n^ = len(str) - len(s) }
 	if s == "" {
 		return
 	}
@@ -588,6 +588,38 @@ parse_f64 :: proc(str: string, n: ^int = nil) -> (value: f64, ok: bool) {
 
 		v := _digit_value(r)
 		if v >= 10 {
+			if r == '.' || r == 'e' || r == 'E' { // Skip parsing NaN and Inf if it's probably a regular float
+				break
+			}
+			if len(s) >= 3 + i {
+				buf: [4]u8
+				copy(buf[:], s[i:][:3])
+
+				v2 := transmute(u32)buf
+				v2 &= 0xDFDFDFDF // Knock out lower-case bits
+
+				buf = transmute([4]u8)v2
+
+				when ODIN_ENDIAN == .Little {
+					if v2 == 0x464e49 { // "INF"
+						s = s[3+i:]
+						value = 0h7ff00000_00000000 if sign == 1 else 0hfff00000_00000000
+						return value, len(s) == 0
+					} else if v2 == 0x4e414e { // "NAN"
+						s = s[3+i:]
+						return 0h7ff80000_00000001, len(s) == 0
+					}
+				} else {
+					if v2 == 0x494e4600 { // "\0FNI"
+						s = s[3+i:]
+						value = 0h7ff00000_00000000 if sign == 1 else 0hfff00000_00000000
+						return value, len(s) == 0
+					} else if v2 == 0x4e414e00 { // "\0NAN"
+						s = s[3+i:]
+						return 0h7ff80000_00000001, len(s) == 0
+					}
+				}
+			}
 			break
 		}
 		value *= 10

+ 4 - 6
tests/issues/run.bat

@@ -2,15 +2,13 @@
 
 if not exist "build\" mkdir build
 
-set COMMON=-collection:tests=.. -out:build\test_issue.exe
+set COMMON=-collection:tests=..
 
 @echo on
 
-..\..\odin build test_issue_829.odin %COMMON% -file
-build\test_issue
-
-..\..\odin build test_issue_1592.odin %COMMON% -file
-build\test_issue
+..\..\odin test test_issue_829.odin %COMMON% -file
+..\..\odin test test_issue_1592.odin %COMMON% -file
+..\..\odin test test_issue_2087.odin %COMMON% -file
 
 @echo off
 

+ 4 - 6
tests/issues/run.sh

@@ -3,15 +3,13 @@ set -eu
 
 mkdir -p build
 ODIN=../../odin
-COMMON="-collection:tests=.. -out:build/test_issue"
+COMMON="-collection:tests=.."
 
 set -x
 
-$ODIN build test_issue_829.odin $COMMON -file
-./build/test_issue
-
-$ODIN build test_issue_1592.odin $COMMON -file
-./build/test_issue
+$ODIN test test_issue_829.odin  $COMMON -file
+$ODIN test test_issue_1592.odin $COMMON -file
+$ODIN test test_issue_2087.odin $COMMON -file
 
 set +x
 

+ 146 - 177
tests/issues/test_issue_1592.odin

@@ -3,36 +3,6 @@ package test_issues
 
 import "core:fmt"
 import "core:testing"
-import tc "tests:common"
-
-main :: proc() {
-	t := testing.T{}
-
-	/* This won't short-circuit */
-	test_orig()
-
-	/* These will short-circuit */
-	test_simple_const_false(&t)
-	test_simple_const_true(&t)
-
-	/* These won't short-circuit */
-	test_simple_proc_false(&t)
-	test_simple_proc_true(&t)
-
-	/* These won't short-circuit */
-	test_const_false_const_false(&t)
-	test_const_false_const_true(&t)
-	test_const_true_const_false(&t)
-	test_const_true_const_true(&t)
-
-	/* These won't short-circuit */
-	test_proc_false_const_false(&t)
-	test_proc_false_const_true(&t)
-	test_proc_true_const_false(&t)
-	test_proc_true_const_true(&t)
-
-	tc.report(&t)
-}
 
 /* Original issue #1592 example */
 
@@ -43,7 +13,6 @@ bool_result :: proc() -> bool {
 	return false
 }
 
-@test
 test_orig :: proc() {
 	if bool_result() || CONSTANT_BOOL {
 	}
@@ -62,428 +31,428 @@ true_result :: proc() -> bool {
 @test
 test_simple_const_false :: proc(t: ^testing.T) {
 	if CONSTANT_FALSE {
-		tc.expect(t, false, fmt.tprintf("%s: !false\n", #procedure))
+		testing.expect(t, false, fmt.tprintf("%s: !false\n", #procedure))
 	} else {
-		tc.expect(t, true, fmt.tprintf("%s: !true\n", #procedure))
+		testing.expect(t, true, fmt.tprintf("%s: !true\n", #procedure))
 	}
 	if (CONSTANT_FALSE) {
-		tc.expect(t, false, fmt.tprintf("%s: !false\n", #procedure))
+		testing.expect(t, false, fmt.tprintf("%s: !false\n", #procedure))
 	} else {
-		tc.expect(t, true, fmt.tprintf("%s: !true\n", #procedure))
+		testing.expect(t, true, fmt.tprintf("%s: !true\n", #procedure))
 	}
 	if !CONSTANT_FALSE {
-		tc.expect(t, true, fmt.tprintf("%s: !true\n", #procedure))
+		testing.expect(t, true, fmt.tprintf("%s: !true\n", #procedure))
 	} else {
-		tc.expect(t, false, fmt.tprintf("%s: !false\n", #procedure))
+		testing.expect(t, false, fmt.tprintf("%s: !false\n", #procedure))
 	}
 	if (!CONSTANT_FALSE) {
-		tc.expect(t, true, fmt.tprintf("%s: !true\n", #procedure))
+		testing.expect(t, true, fmt.tprintf("%s: !true\n", #procedure))
 	} else {
-		tc.expect(t, false, fmt.tprintf("%s: !false\n", #procedure))
+		testing.expect(t, false, fmt.tprintf("%s: !false\n", #procedure))
 	}
 	if !(CONSTANT_FALSE) {
-		tc.expect(t, true, fmt.tprintf("%s: !true\n", #procedure))
+		testing.expect(t, true, fmt.tprintf("%s: !true\n", #procedure))
 	} else {
-		tc.expect(t, false, fmt.tprintf("%s: !false\n", #procedure))
+		testing.expect(t, false, fmt.tprintf("%s: !false\n", #procedure))
 	}
 	if !!CONSTANT_FALSE {
-		tc.expect(t, false, fmt.tprintf("%s: !false\n", #procedure))
+		testing.expect(t, false, fmt.tprintf("%s: !false\n", #procedure))
 	} else {
-		tc.expect(t, true, fmt.tprintf("%s: !true\n", #procedure))
+		testing.expect(t, true, fmt.tprintf("%s: !true\n", #procedure))
 	}
 	if CONSTANT_FALSE == true {
-		tc.expect(t, false, fmt.tprintf("%s: !false\n", #procedure))
+		testing.expect(t, false, fmt.tprintf("%s: !false\n", #procedure))
 	} else {
-		tc.expect(t, true, fmt.tprintf("%s: !true\n", #procedure))
+		testing.expect(t, true, fmt.tprintf("%s: !true\n", #procedure))
 	}
 	if CONSTANT_FALSE == false {
-		tc.expect(t, true, fmt.tprintf("%s: !true\n", #procedure))
+		testing.expect(t, true, fmt.tprintf("%s: !true\n", #procedure))
 	} else {
-		tc.expect(t, false, fmt.tprintf("%s: !false\n", #procedure))
+		testing.expect(t, false, fmt.tprintf("%s: !false\n", #procedure))
 	}
 	if !(CONSTANT_FALSE == true) {
-		tc.expect(t, true, fmt.tprintf("%s: !true\n", #procedure))
+		testing.expect(t, true, fmt.tprintf("%s: !true\n", #procedure))
 	} else {
-		tc.expect(t, false, fmt.tprintf("%s: !false\n", #procedure))
+		testing.expect(t, false, fmt.tprintf("%s: !false\n", #procedure))
 	}
 	if !(CONSTANT_FALSE == false) {
-		tc.expect(t, false, fmt.tprintf("%s: !false\n", #procedure))
+		testing.expect(t, false, fmt.tprintf("%s: !false\n", #procedure))
 	} else {
-		tc.expect(t, true, fmt.tprintf("%s: !true\n", #procedure))
+		testing.expect(t, true, fmt.tprintf("%s: !true\n", #procedure))
 	}
 }
 
 @test
 test_simple_const_true :: proc(t: ^testing.T) {
 	if CONSTANT_TRUE {
-		tc.expect(t, true, fmt.tprintf("%s: !true\n", #procedure))
+		testing.expect(t, true, fmt.tprintf("%s: !true\n", #procedure))
 	} else {
-		tc.expect(t, false, fmt.tprintf("%s: !false\n", #procedure))
+		testing.expect(t, false, fmt.tprintf("%s: !false\n", #procedure))
 	}
 	if (CONSTANT_TRUE) {
-		tc.expect(t, true, fmt.tprintf("%s: !true\n", #procedure))
+		testing.expect(t, true, fmt.tprintf("%s: !true\n", #procedure))
 	} else {
-		tc.expect(t, false, fmt.tprintf("%s: !false\n", #procedure))
+		testing.expect(t, false, fmt.tprintf("%s: !false\n", #procedure))
 	}
 	if !CONSTANT_TRUE {
-		tc.expect(t, false, fmt.tprintf("%s: !false\n", #procedure))
+		testing.expect(t, false, fmt.tprintf("%s: !false\n", #procedure))
 	} else {
-		tc.expect(t, true, fmt.tprintf("%s: !true\n", #procedure))
+		testing.expect(t, true, fmt.tprintf("%s: !true\n", #procedure))
 	}
 	if (!CONSTANT_TRUE) {
-		tc.expect(t, false, fmt.tprintf("%s: !false\n", #procedure))
+		testing.expect(t, false, fmt.tprintf("%s: !false\n", #procedure))
 	} else {
-		tc.expect(t, true, fmt.tprintf("%s: !true\n", #procedure))
+		testing.expect(t, true, fmt.tprintf("%s: !true\n", #procedure))
 	}
 	if (!CONSTANT_TRUE) {
-		tc.expect(t, false, fmt.tprintf("%s: !false\n", #procedure))
+		testing.expect(t, false, fmt.tprintf("%s: !false\n", #procedure))
 	} else {
-		tc.expect(t, true, fmt.tprintf("%s: !true\n", #procedure))
+		testing.expect(t, true, fmt.tprintf("%s: !true\n", #procedure))
 	}
 	if !(CONSTANT_TRUE) {
-		tc.expect(t, false, fmt.tprintf("%s: !false\n", #procedure))
+		testing.expect(t, false, fmt.tprintf("%s: !false\n", #procedure))
 	} else {
-		tc.expect(t, true, fmt.tprintf("%s: !true\n", #procedure))
+		testing.expect(t, true, fmt.tprintf("%s: !true\n", #procedure))
 	}
 	if !!CONSTANT_TRUE {
-		tc.expect(t, true, fmt.tprintf("%s: !true\n", #procedure))
+		testing.expect(t, true, fmt.tprintf("%s: !true\n", #procedure))
 	} else {
-		tc.expect(t, false, fmt.tprintf("%s: !false\n", #procedure))
+		testing.expect(t, false, fmt.tprintf("%s: !false\n", #procedure))
 	}
 	if CONSTANT_TRUE == true {
-		tc.expect(t, true, fmt.tprintf("%s: !true\n", #procedure))
+		testing.expect(t, true, fmt.tprintf("%s: !true\n", #procedure))
 	} else {
-		tc.expect(t, false, fmt.tprintf("%s: !false\n", #procedure))
+		testing.expect(t, false, fmt.tprintf("%s: !false\n", #procedure))
 	}
 	if CONSTANT_TRUE == false {
-		tc.expect(t, false, fmt.tprintf("%s: !false\n", #procedure))
+		testing.expect(t, false, fmt.tprintf("%s: !false\n", #procedure))
 	} else {
-		tc.expect(t, true, fmt.tprintf("%s: !true\n", #procedure))
+		testing.expect(t, true, fmt.tprintf("%s: !true\n", #procedure))
 	}
 	if !(CONSTANT_TRUE == true) {
-		tc.expect(t, false, fmt.tprintf("%s: !false\n", #procedure))
+		testing.expect(t, false, fmt.tprintf("%s: !false\n", #procedure))
 	} else {
-		tc.expect(t, true, fmt.tprintf("%s: !true\n", #procedure))
+		testing.expect(t, true, fmt.tprintf("%s: !true\n", #procedure))
 	}
 	if !(CONSTANT_TRUE == false) {
-		tc.expect(t, true, fmt.tprintf("%s: !true\n", #procedure))
+		testing.expect(t, true, fmt.tprintf("%s: !true\n", #procedure))
 	} else {
-		tc.expect(t, false, fmt.tprintf("%s: !false\n", #procedure))
+		testing.expect(t, false, fmt.tprintf("%s: !false\n", #procedure))
 	}
 }
 
 @test
 test_simple_proc_false :: proc(t: ^testing.T) {
 	if false_result() {
-		tc.expect(t, false, fmt.tprintf("%s: !false\n", #procedure))
+		testing.expect(t, false, fmt.tprintf("%s: !false\n", #procedure))
 	} else {
-		tc.expect(t, true, fmt.tprintf("%s: !true\n", #procedure))
+		testing.expect(t, true, fmt.tprintf("%s: !true\n", #procedure))
 	}
 	if !false_result() {
-		tc.expect(t, true, fmt.tprintf("%s: !true\n", #procedure))
+		testing.expect(t, true, fmt.tprintf("%s: !true\n", #procedure))
 	} else {
-		tc.expect(t, false, fmt.tprintf("%s: !false\n", #procedure))
+		testing.expect(t, false, fmt.tprintf("%s: !false\n", #procedure))
 	}
 }
 
 @test
 test_simple_proc_true :: proc(t: ^testing.T) {
 	if true_result() {
-		tc.expect(t, true, fmt.tprintf("%s: !true\n", #procedure))
+		testing.expect(t, true, fmt.tprintf("%s: !true\n", #procedure))
 	} else {
-		tc.expect(t, false, fmt.tprintf("%s: !false\n", #procedure))
+		testing.expect(t, false, fmt.tprintf("%s: !false\n", #procedure))
 	}
 	if !true_result() {
-		tc.expect(t, false, fmt.tprintf("%s: !false\n", #procedure))
+		testing.expect(t, false, fmt.tprintf("%s: !false\n", #procedure))
 	} else {
-		tc.expect(t, true, fmt.tprintf("%s: !true\n", #procedure))
+		testing.expect(t, true, fmt.tprintf("%s: !true\n", #procedure))
 	}
 }
 
 @test
 test_const_false_const_false :: proc(t: ^testing.T) {
 	if CONSTANT_FALSE || CONSTANT_FALSE {
-		tc.expect(t, false, fmt.tprintf("%s: !false\n", #procedure))
+		testing.expect(t, false, fmt.tprintf("%s: !false\n", #procedure))
 	} else {
-		tc.expect(t, true, fmt.tprintf("%s: !true\n", #procedure))
+		testing.expect(t, true, fmt.tprintf("%s: !true\n", #procedure))
 	}
 	if CONSTANT_FALSE && CONSTANT_FALSE {
-		tc.expect(t, false, fmt.tprintf("%s: !false\n", #procedure))
+		testing.expect(t, false, fmt.tprintf("%s: !false\n", #procedure))
 	} else {
-		tc.expect(t, true, fmt.tprintf("%s: !true\n", #procedure))
+		testing.expect(t, true, fmt.tprintf("%s: !true\n", #procedure))
 	}
 
 	if !CONSTANT_FALSE || CONSTANT_FALSE {
-		tc.expect(t, true, fmt.tprintf("%s: !true\n", #procedure))
+		testing.expect(t, true, fmt.tprintf("%s: !true\n", #procedure))
 	} else {
-		tc.expect(t, false, fmt.tprintf("%s: !false\n", #procedure))
+		testing.expect(t, false, fmt.tprintf("%s: !false\n", #procedure))
 	}
 	if !CONSTANT_FALSE && CONSTANT_FALSE {
-		tc.expect(t, false, fmt.tprintf("%s: !false\n", #procedure))
+		testing.expect(t, false, fmt.tprintf("%s: !false\n", #procedure))
 	} else {
-		tc.expect(t, true, fmt.tprintf("%s: !true\n", #procedure))
+		testing.expect(t, true, fmt.tprintf("%s: !true\n", #procedure))
 	}
 
 	if CONSTANT_FALSE || !CONSTANT_FALSE {
-		tc.expect(t, true, fmt.tprintf("%s: !true\n", #procedure))
+		testing.expect(t, true, fmt.tprintf("%s: !true\n", #procedure))
 	} else {
-		tc.expect(t, false, fmt.tprintf("%s: !false\n", #procedure))
+		testing.expect(t, false, fmt.tprintf("%s: !false\n", #procedure))
 	}
 	if CONSTANT_FALSE && !CONSTANT_FALSE {
-		tc.expect(t, false, fmt.tprintf("%s: !false\n", #procedure))
+		testing.expect(t, false, fmt.tprintf("%s: !false\n", #procedure))
 	} else {
-		tc.expect(t, true, fmt.tprintf("%s: !true\n", #procedure))
+		testing.expect(t, true, fmt.tprintf("%s: !true\n", #procedure))
 	}
 
 	if !(CONSTANT_FALSE || CONSTANT_FALSE) {
-		tc.expect(t, true, fmt.tprintf("%s: !true\n", #procedure))
+		testing.expect(t, true, fmt.tprintf("%s: !true\n", #procedure))
 	} else {
-		tc.expect(t, false, fmt.tprintf("%s: !false\n", #procedure))
+		testing.expect(t, false, fmt.tprintf("%s: !false\n", #procedure))
 	}
 	if !(CONSTANT_FALSE && CONSTANT_FALSE) {
-		tc.expect(t, true, fmt.tprintf("%s: !true\n", #procedure))
+		testing.expect(t, true, fmt.tprintf("%s: !true\n", #procedure))
 	} else {
-		tc.expect(t, false, fmt.tprintf("%s: !false\n", #procedure))
+		testing.expect(t, false, fmt.tprintf("%s: !false\n", #procedure))
 	}
 }
 
 @test
 test_const_false_const_true :: proc(t: ^testing.T) {
 	if CONSTANT_FALSE || CONSTANT_TRUE {
-		tc.expect(t, true, fmt.tprintf("%s: !true\n", #procedure))
+		testing.expect(t, true, fmt.tprintf("%s: !true\n", #procedure))
 	} else {
-		tc.expect(t, false, fmt.tprintf("%s: !false\n", #procedure))
+		testing.expect(t, false, fmt.tprintf("%s: !false\n", #procedure))
 	}
 	if CONSTANT_FALSE && CONSTANT_TRUE {
-		tc.expect(t, false, fmt.tprintf("%s: !false\n", #procedure))
+		testing.expect(t, false, fmt.tprintf("%s: !false\n", #procedure))
 	} else {
-		tc.expect(t, true, fmt.tprintf("%s: !true\n", #procedure))
+		testing.expect(t, true, fmt.tprintf("%s: !true\n", #procedure))
 	}
 
 	if !CONSTANT_FALSE || CONSTANT_TRUE {
-		tc.expect(t, true, fmt.tprintf("%s: !true\n", #procedure))
+		testing.expect(t, true, fmt.tprintf("%s: !true\n", #procedure))
 	} else {
-		tc.expect(t, false, fmt.tprintf("%s: !false\n", #procedure))
+		testing.expect(t, false, fmt.tprintf("%s: !false\n", #procedure))
 	}
 	if !CONSTANT_FALSE && CONSTANT_TRUE {
-		tc.expect(t, true, fmt.tprintf("%s: !true\n", #procedure))
+		testing.expect(t, true, fmt.tprintf("%s: !true\n", #procedure))
 	} else {
-		tc.expect(t, false, fmt.tprintf("%s: !false\n", #procedure))
+		testing.expect(t, false, fmt.tprintf("%s: !false\n", #procedure))
 	}
 
 	if CONSTANT_FALSE || !CONSTANT_TRUE {
-		tc.expect(t, false, fmt.tprintf("%s: !false\n", #procedure))
+		testing.expect(t, false, fmt.tprintf("%s: !false\n", #procedure))
 	} else {
-		tc.expect(t, true, fmt.tprintf("%s: !true\n", #procedure))
+		testing.expect(t, true, fmt.tprintf("%s: !true\n", #procedure))
 	}
 	if CONSTANT_FALSE && !CONSTANT_TRUE {
-		tc.expect(t, false, fmt.tprintf("%s: !false\n", #procedure))
+		testing.expect(t, false, fmt.tprintf("%s: !false\n", #procedure))
 	} else {
-		tc.expect(t, true, fmt.tprintf("%s: !true\n", #procedure))
+		testing.expect(t, true, fmt.tprintf("%s: !true\n", #procedure))
 	}
 
 	if !(CONSTANT_FALSE || CONSTANT_TRUE) {
-		tc.expect(t, false, fmt.tprintf("%s: !false\n", #procedure))
+		testing.expect(t, false, fmt.tprintf("%s: !false\n", #procedure))
 	} else {
-		tc.expect(t, true, fmt.tprintf("%s: !true\n", #procedure))
+		testing.expect(t, true, fmt.tprintf("%s: !true\n", #procedure))
 	}
 	if !(CONSTANT_FALSE && CONSTANT_TRUE) {
-		tc.expect(t, true, fmt.tprintf("%s: !true\n", #procedure))
+		testing.expect(t, true, fmt.tprintf("%s: !true\n", #procedure))
 	} else {
-		tc.expect(t, false, fmt.tprintf("%s: !false\n", #procedure))
+		testing.expect(t, false, fmt.tprintf("%s: !false\n", #procedure))
 	}
 }
 
 @test
 test_const_true_const_false :: proc(t: ^testing.T) {
 	if CONSTANT_TRUE || CONSTANT_FALSE {
-		tc.expect(t, true, fmt.tprintf("%s: !true\n", #procedure))
+		testing.expect(t, true, fmt.tprintf("%s: !true\n", #procedure))
 	} else {
-		tc.expect(t, false, fmt.tprintf("%s: !false\n", #procedure))
+		testing.expect(t, false, fmt.tprintf("%s: !false\n", #procedure))
 	}
 	if CONSTANT_TRUE && CONSTANT_FALSE {
-		tc.expect(t, false, fmt.tprintf("%s: !false\n", #procedure))
+		testing.expect(t, false, fmt.tprintf("%s: !false\n", #procedure))
 	} else {
-		tc.expect(t, true, fmt.tprintf("%s: !true\n", #procedure))
+		testing.expect(t, true, fmt.tprintf("%s: !true\n", #procedure))
 	}
 
 	if !CONSTANT_TRUE || CONSTANT_FALSE {
-		tc.expect(t, false, fmt.tprintf("%s: !false\n", #procedure))
+		testing.expect(t, false, fmt.tprintf("%s: !false\n", #procedure))
 	} else {
-		tc.expect(t, true, fmt.tprintf("%s: !true\n", #procedure))
+		testing.expect(t, true, fmt.tprintf("%s: !true\n", #procedure))
 	}
 	if !CONSTANT_TRUE && CONSTANT_FALSE {
-		tc.expect(t, false, fmt.tprintf("%s: !false\n", #procedure))
+		testing.expect(t, false, fmt.tprintf("%s: !false\n", #procedure))
 	} else {
-		tc.expect(t, true, fmt.tprintf("%s: !true\n", #procedure))
+		testing.expect(t, true, fmt.tprintf("%s: !true\n", #procedure))
 	}
 
 	if CONSTANT_TRUE || !CONSTANT_FALSE {
-		tc.expect(t, true, fmt.tprintf("%s: !true\n", #procedure))
+		testing.expect(t, true, fmt.tprintf("%s: !true\n", #procedure))
 	} else {
-		tc.expect(t, false, fmt.tprintf("%s: !false\n", #procedure))
+		testing.expect(t, false, fmt.tprintf("%s: !false\n", #procedure))
 	}
 	if CONSTANT_TRUE && !CONSTANT_FALSE {
-		tc.expect(t, true, fmt.tprintf("%s: !true\n", #procedure))
+		testing.expect(t, true, fmt.tprintf("%s: !true\n", #procedure))
 	} else {
-		tc.expect(t, false, fmt.tprintf("%s: !false\n", #procedure))
+		testing.expect(t, false, fmt.tprintf("%s: !false\n", #procedure))
 	}
 
 	if !(CONSTANT_TRUE || CONSTANT_FALSE) {
-		tc.expect(t, false, fmt.tprintf("%s: !false\n", #procedure))
+		testing.expect(t, false, fmt.tprintf("%s: !false\n", #procedure))
 	} else {
-		tc.expect(t, true, fmt.tprintf("%s: !true\n", #procedure))
+		testing.expect(t, true, fmt.tprintf("%s: !true\n", #procedure))
 	}
 	if !(CONSTANT_TRUE && CONSTANT_FALSE) {
-		tc.expect(t, true, fmt.tprintf("%s: !true\n", #procedure))
+		testing.expect(t, true, fmt.tprintf("%s: !true\n", #procedure))
 	} else {
-		tc.expect(t, false, fmt.tprintf("%s: !false\n", #procedure))
+		testing.expect(t, false, fmt.tprintf("%s: !false\n", #procedure))
 	}
 }
 
 @test
 test_const_true_const_true :: proc(t: ^testing.T) {
 	if CONSTANT_TRUE || CONSTANT_TRUE {
-		tc.expect(t, true, fmt.tprintf("%s: !true\n", #procedure))
+		testing.expect(t, true, fmt.tprintf("%s: !true\n", #procedure))
 	} else {
-		tc.expect(t, false, fmt.tprintf("%s: !false\n", #procedure))
+		testing.expect(t, false, fmt.tprintf("%s: !false\n", #procedure))
 	}
 	if CONSTANT_TRUE && CONSTANT_TRUE {
-		tc.expect(t, true, fmt.tprintf("%s: !true\n", #procedure))
+		testing.expect(t, true, fmt.tprintf("%s: !true\n", #procedure))
 	} else {
-		tc.expect(t, false, fmt.tprintf("%s: !false\n", #procedure))
+		testing.expect(t, false, fmt.tprintf("%s: !false\n", #procedure))
 	}
 
 	if !CONSTANT_TRUE || CONSTANT_TRUE {
-		tc.expect(t, true, fmt.tprintf("%s: !true\n", #procedure))
+		testing.expect(t, true, fmt.tprintf("%s: !true\n", #procedure))
 	} else {
-		tc.expect(t, false, fmt.tprintf("%s: !false\n", #procedure))
+		testing.expect(t, false, fmt.tprintf("%s: !false\n", #procedure))
 	}
 	if !CONSTANT_TRUE && CONSTANT_TRUE {
-		tc.expect(t, false, fmt.tprintf("%s: !false\n", #procedure))
+		testing.expect(t, false, fmt.tprintf("%s: !false\n", #procedure))
 	} else {
-		tc.expect(t, true, fmt.tprintf("%s: !true\n", #procedure))
+		testing.expect(t, true, fmt.tprintf("%s: !true\n", #procedure))
 	}
 
 	if CONSTANT_TRUE || !CONSTANT_TRUE {
-		tc.expect(t, true, fmt.tprintf("%s: !true\n", #procedure))
+		testing.expect(t, true, fmt.tprintf("%s: !true\n", #procedure))
 	} else {
-		tc.expect(t, false, fmt.tprintf("%s: !false\n", #procedure))
+		testing.expect(t, false, fmt.tprintf("%s: !false\n", #procedure))
 	}
 	if CONSTANT_TRUE && !CONSTANT_TRUE {
-		tc.expect(t, false, fmt.tprintf("%s: !false\n", #procedure))
+		testing.expect(t, false, fmt.tprintf("%s: !false\n", #procedure))
 	} else {
-		tc.expect(t, true, fmt.tprintf("%s: !true\n", #procedure))
+		testing.expect(t, true, fmt.tprintf("%s: !true\n", #procedure))
 	}
 
 	if !(CONSTANT_TRUE || CONSTANT_TRUE) {
-		tc.expect(t, false, fmt.tprintf("%s: !false\n", #procedure))
+		testing.expect(t, false, fmt.tprintf("%s: !false\n", #procedure))
 	} else {
-		tc.expect(t, true, fmt.tprintf("%s: !true\n", #procedure))
+		testing.expect(t, true, fmt.tprintf("%s: !true\n", #procedure))
 	}
 	if !(CONSTANT_TRUE && CONSTANT_TRUE) {
-		tc.expect(t, false, fmt.tprintf("%s: !false\n", #procedure))
+		testing.expect(t, false, fmt.tprintf("%s: !false\n", #procedure))
 	} else {
-		tc.expect(t, true, fmt.tprintf("%s: !true\n", #procedure))
+		testing.expect(t, true, fmt.tprintf("%s: !true\n", #procedure))
 	}
 }
 
 @test
 test_proc_false_const_false :: proc(t: ^testing.T) {
 	if false_result() || CONSTANT_FALSE {
-		tc.expect(t, false, fmt.tprintf("%s: !false\n", #procedure))
+		testing.expect(t, false, fmt.tprintf("%s: !false\n", #procedure))
 	} else {
-		tc.expect(t, true, fmt.tprintf("%s: !true\n", #procedure))
+		testing.expect(t, true, fmt.tprintf("%s: !true\n", #procedure))
 	}
 	if false_result() && CONSTANT_FALSE {
-		tc.expect(t, false, fmt.tprintf("%s: !false\n", #procedure))
+		testing.expect(t, false, fmt.tprintf("%s: !false\n", #procedure))
 	} else {
-		tc.expect(t, true, fmt.tprintf("%s: !true\n", #procedure))
+		testing.expect(t, true, fmt.tprintf("%s: !true\n", #procedure))
 	}
 
 	if !(false_result() || CONSTANT_FALSE) {
-		tc.expect(t, true, fmt.tprintf("%s: !true\n", #procedure))
+		testing.expect(t, true, fmt.tprintf("%s: !true\n", #procedure))
 	} else {
-		tc.expect(t, false, fmt.tprintf("%s: !false\n", #procedure))
+		testing.expect(t, false, fmt.tprintf("%s: !false\n", #procedure))
 	}
 	if !(false_result() && CONSTANT_FALSE) {
-		tc.expect(t, true, fmt.tprintf("%s: !true\n", #procedure))
+		testing.expect(t, true, fmt.tprintf("%s: !true\n", #procedure))
 	} else {
-		tc.expect(t, false, fmt.tprintf("%s: !false\n", #procedure))
+		testing.expect(t, false, fmt.tprintf("%s: !false\n", #procedure))
 	}
 }
 
 @test
 test_proc_false_const_true :: proc(t: ^testing.T) {
 	if false_result() || CONSTANT_TRUE {
-		tc.expect(t, true, fmt.tprintf("%s: !true\n", #procedure))
+		testing.expect(t, true, fmt.tprintf("%s: !true\n", #procedure))
 	} else {
-		tc.expect(t, false, fmt.tprintf("%s: !false\n", #procedure))
+		testing.expect(t, false, fmt.tprintf("%s: !false\n", #procedure))
 	}
 	if false_result() && CONSTANT_TRUE {
-		tc.expect(t, false, fmt.tprintf("%s: !false\n", #procedure))
+		testing.expect(t, false, fmt.tprintf("%s: !false\n", #procedure))
 	} else {
-		tc.expect(t, true, fmt.tprintf("%s: !true\n", #procedure))
+		testing.expect(t, true, fmt.tprintf("%s: !true\n", #procedure))
 	}
 
 	if !(false_result() || CONSTANT_TRUE) {
-		tc.expect(t, false, fmt.tprintf("%s: !false\n", #procedure))
+		testing.expect(t, false, fmt.tprintf("%s: !false\n", #procedure))
 	} else {
-		tc.expect(t, true, fmt.tprintf("%s: !true\n", #procedure))
+		testing.expect(t, true, fmt.tprintf("%s: !true\n", #procedure))
 	}
 	if !(false_result() && CONSTANT_TRUE) {
-		tc.expect(t, true, fmt.tprintf("%s: !true\n", #procedure))
+		testing.expect(t, true, fmt.tprintf("%s: !true\n", #procedure))
 	} else {
-		tc.expect(t, false, fmt.tprintf("%s: !false\n", #procedure))
+		testing.expect(t, false, fmt.tprintf("%s: !false\n", #procedure))
 	}
 }
 
 @test
 test_proc_true_const_false :: proc(t: ^testing.T) {
 	if true_result() || CONSTANT_FALSE {
-		tc.expect(t, true, fmt.tprintf("%s: !true\n", #procedure))
+		testing.expect(t, true, fmt.tprintf("%s: !true\n", #procedure))
 	} else {
-		tc.expect(t, false, fmt.tprintf("%s: !false\n", #procedure))
+		testing.expect(t, false, fmt.tprintf("%s: !false\n", #procedure))
 	}
 	if true_result() && CONSTANT_FALSE {
-		tc.expect(t, false, fmt.tprintf("%s: !false\n", #procedure))
+		testing.expect(t, false, fmt.tprintf("%s: !false\n", #procedure))
 	} else {
-		tc.expect(t, true, fmt.tprintf("%s: !true\n", #procedure))
+		testing.expect(t, true, fmt.tprintf("%s: !true\n", #procedure))
 	}
 
 	if !(true_result() || CONSTANT_FALSE) {
-		tc.expect(t, false, fmt.tprintf("%s: !false\n", #procedure))
+		testing.expect(t, false, fmt.tprintf("%s: !false\n", #procedure))
 	} else {
-		tc.expect(t, true, fmt.tprintf("%s: !true\n", #procedure))
+		testing.expect(t, true, fmt.tprintf("%s: !true\n", #procedure))
 	}
 	if !(true_result() && CONSTANT_FALSE) {
-		tc.expect(t, true, fmt.tprintf("%s: !true\n", #procedure))
+		testing.expect(t, true, fmt.tprintf("%s: !true\n", #procedure))
 	} else {
-		tc.expect(t, false, fmt.tprintf("%s: !false\n", #procedure))
+		testing.expect(t, false, fmt.tprintf("%s: !false\n", #procedure))
 	}
 }
 
 @test
 test_proc_true_const_true :: proc(t: ^testing.T) {
 	if true_result() || CONSTANT_TRUE {
-		tc.expect(t, true, fmt.tprintf("%s: !true\n", #procedure))
+		testing.expect(t, true, fmt.tprintf("%s: !true\n", #procedure))
 	} else {
-		tc.expect(t, false, fmt.tprintf("%s: !false\n", #procedure))
+		testing.expect(t, false, fmt.tprintf("%s: !false\n", #procedure))
 	}
 	if true_result() && CONSTANT_TRUE {
-		tc.expect(t, true, fmt.tprintf("%s: !true\n", #procedure))
+		testing.expect(t, true, fmt.tprintf("%s: !true\n", #procedure))
 	} else {
-		tc.expect(t, false, fmt.tprintf("%s: !false\n", #procedure))
+		testing.expect(t, false, fmt.tprintf("%s: !false\n", #procedure))
 	}
 
 	if !(true_result() || CONSTANT_TRUE) {
-		tc.expect(t, false, fmt.tprintf("%s: !false\n", #procedure))
+		testing.expect(t, false, fmt.tprintf("%s: !false\n", #procedure))
 	} else {
-		tc.expect(t, true, fmt.tprintf("%s: !true\n", #procedure))
+		testing.expect(t, true, fmt.tprintf("%s: !true\n", #procedure))
 	}
 	if !(true_result() && CONSTANT_TRUE) {
-		tc.expect(t, false, fmt.tprintf("%s: !false\n", #procedure))
+		testing.expect(t, false, fmt.tprintf("%s: !false\n", #procedure))
 	} else {
-		tc.expect(t, true, fmt.tprintf("%s: !true\n", #procedure))
+		testing.expect(t, true, fmt.tprintf("%s: !true\n", #procedure))
 	}
 }

+ 58 - 0
tests/issues/test_issue_2087.odin

@@ -0,0 +1,58 @@
+// 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("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")
+	}
+}

+ 2 - 17
tests/issues/test_issue_829.odin

@@ -3,31 +3,16 @@ package test_issues
 
 import "core:fmt"
 import "core:testing"
-import tc "tests:common"
 
 /* Original issue #829 example */
-
 env : map[string]proc(a, b : int) -> int = {
 	"+" = proc(a, b : int) -> int {
 		return a + b
 	},
 }
 
-test_orig :: proc() {
-	fmt.println(env["+"](1, 2))
-}
-
-main :: proc() {
-	t := testing.T{}
-
-	test_orig()
-
-	test_orig_ret(&t)
-
-	tc.report(&t)
-}
-
+@(test)
 test_orig_ret :: proc(t: ^testing.T) {
 	r := fmt.tprint(env["+"](1, 2))
-	tc.expect(t, r == "3", fmt.tprintf("%s: \"%s\" != \"3\"\n", #procedure, r))
+	testing.expect(t, r == "3", fmt.tprintf("%s: \"%s\" != \"3\"\n", #procedure, r))
 }