Browse Source

Fix parsing C-like hex floats

gingerBill 2 years ago
parent
commit
ff275df5ea
1 changed files with 39 additions and 11 deletions
  1. 39 11
      core/strconv/strconv.odin

+ 39 - 11
core/strconv/strconv.odin

@@ -556,19 +556,49 @@ parse_f32 :: proc(s: string, n: ^int = nil) -> (value: f32, ok: bool) {
 	return f32(v), ok
 	return f32(v), ok
 }
 }
 
 
+
+parse_f64 :: proc(str: string, n: ^int = nil) -> (value: f64, ok: bool) {
+	value, n^, ok = parse_f64_prefix(str)
+	if ok && len(str) != n^ {
+		ok = false
+	}
+	return
+}
+
+
+// Parses a 32-bit floating point number from a string.
+//
+// Returns ok=false if a base 10 float could not be found,
+// or if the input string contained more than just the number.
+//
+// ```
+// n, _, ok := strconv.parse_f32("12.34eee");
+// assert(n == 12.34 && ok);
+//
+// n, _, ok = strconv.parse_f32("12.34");
+// assert(n == 12.34 && ok);
+// ```
+parse_f32_prefix :: proc(str: string) -> (value: f32, nr: int, ok: bool) {
+	f: f64
+	f, nr, ok = parse_f64_prefix(str)
+	value = f32(f)
+	return
+}
+
+
 // Parses a 64-bit floating point number from a string.
 // Parses a 64-bit floating point number from a string.
 //
 //
 // Returns ok=false if a base 10 float could not be found,
 // Returns ok=false if a base 10 float could not be found,
 // or if the input string contained more than just the number.
 // or if the input string contained more than just the number.
 //
 //
 // ```
 // ```
-// n, ok := strconv.parse_f32("12.34eee");
+// n, _, ok := strconv.parse_f32("12.34eee");
 // assert(n == 12.34 && ok);
 // assert(n == 12.34 && ok);
 //
 //
-// n, ok = strconv.parse_f32("12.34");
+// n, _, ok = strconv.parse_f32("12.34");
 // assert(n == 12.34 && ok);
 // assert(n == 12.34 && ok);
 // ```
 // ```
-parse_f64 :: proc(str: string, n: ^int = nil) -> (value: f64, ok: bool) {
+parse_f64_prefix :: proc(str: string) -> (value: f64, nr: int, ok: bool) {
 	common_prefix_len_ignore_case :: proc "contextless" (s, prefix: string) -> int {
 	common_prefix_len_ignore_case :: proc "contextless" (s, prefix: string) -> int {
 		n := len(prefix)
 		n := len(prefix)
 		if n > len(s) {
 		if n > len(s) {
@@ -751,7 +781,7 @@ parse_f64 :: proc(str: string, n: ^int = nil) -> (value: f64, ok: bool) {
 			mantissa |= 1
 			mantissa |= 1
 		}
 		}
 
 
-		for mantissa >> (info.mantbits+2) == 0 {
+		for mantissa != 0 && mantissa >> (info.mantbits+2) == 0 {
 			mantissa = mantissa>>1 | mantissa&1
 			mantissa = mantissa>>1 | mantissa&1
 			exp += 1
 			exp += 1
 		}
 		}
@@ -795,9 +825,6 @@ parse_f64 :: proc(str: string, n: ^int = nil) -> (value: f64, ok: bool) {
 	}
 	}
 
 
 
 
-	nr: int
-	defer if n != nil { n^ = nr }
-
 	if value, nr, ok = check_special(str); ok {
 	if value, nr, ok = check_special(str); ok {
 		return
 		return
 	}
 	}
@@ -808,7 +835,8 @@ parse_f64 :: proc(str: string, n: ^int = nil) -> (value: f64, ok: bool) {
 	mantissa, exp, neg, trunc, hex, nr = parse_components(str) or_return
 	mantissa, exp, neg, trunc, hex, nr = parse_components(str) or_return
 
 
 	if hex {
 	if hex {
-		return parse_hex(str, mantissa, exp, neg, trunc)
+		value, ok = parse_hex(str, mantissa, exp, neg, trunc)
+		return
 	}
 	}
 
 
 	trunc_block: if !trunc {
 	trunc_block: if !trunc {
@@ -827,7 +855,7 @@ parse_f64 :: proc(str: string, n: ^int = nil) -> (value: f64, ok: bool) {
 		}
 		}
 		switch {
 		switch {
 		case exp == 0:
 		case exp == 0:
-			return f, true
+			return f, nr, true
 		case exp > 0 && exp <= 15+22:
 		case exp > 0 && exp <= 15+22:
 			if exp > 22 {
 			if exp > 22 {
 				f *= pow10[exp-22]
 				f *= pow10[exp-22]
@@ -836,9 +864,9 @@ parse_f64 :: proc(str: string, n: ^int = nil) -> (value: f64, ok: bool) {
 			if f > 1e15 || f < 1e-15 {
 			if f > 1e15 || f < 1e-15 {
 				break trunc_block
 				break trunc_block
 			}
 			}
-			return f * pow10[exp], true
+			return f * pow10[exp], nr, true
 		case -22 <= exp && exp < 0:
 		case -22 <= exp && exp < 0:
-			return f / pow10[-exp], true
+			return f / pow10[-exp], nr, true
 		}
 		}
 	}
 	}
 	d: decimal.Decimal
 	d: decimal.Decimal