summary refs log tree commit diff stats
path: root/lib
diff options
context:
space:
mode:
authorTimothee Cour <timothee.cour2@gmail.com>2021-06-12 22:32:47 -0700
committerGitHub <noreply@github.com>2021-06-13 07:32:47 +0200
commitc871e22da2ad8f9caf82fdba43fccb7230d726e1 (patch)
treedb5cd73be7c460babf50ad1131abe69be959e6a3 /lib
parent897e50d5fe274850d4772612a90b325e33cca8a2 (diff)
downloadNim-c871e22da2ad8f9caf82fdba43fccb7230d726e1.tar.gz
fix #7717 roundtrip float to string; fix `parseFloat` for js (#18248)
* refs #7717 roundtrip float to string
* make parseFloat more correct
* improve float tests
* improve float tests
* cleanup
Diffstat (limited to 'lib')
-rw-r--r--lib/system/jssys.nim89
1 files changed, 41 insertions, 48 deletions
diff --git a/lib/system/jssys.nim b/lib/system/jssys.nim
index 371cb7962..7cb5652c5 100644
--- a/lib/system/jssys.nim
+++ b/lib/system/jssys.nim
@@ -716,19 +716,23 @@ proc tenToThePowerOf(b: int): BiggestFloat =
 const
   IdentChars = {'a'..'z', 'A'..'Z', '0'..'9', '_'}
 
-# XXX use JS's native way here
-proc nimParseBiggestFloat(s: string, number: var BiggestFloat, start = 0): int {.
-                          compilerproc.} =
-  var
-    esign = 1.0
-    sign = 1.0
-    i = start
-    exponent: int
-    flags: int
-  number = 0.0
+
+proc parseFloatNative(a: string): float =
+  let a2 = a.cstring
+  asm """
+  `result` = Number(`a2`);
+  """
+
+#[
+xxx how come code like this doesn't give IndexDefect ?
+let z = s[10000] == 'a'
+]#
+proc nimParseBiggestFloat(s: string, number: var BiggestFloat, start: int): int {.compilerproc.} =
+  var sign: bool
+  var i = start
   if s[i] == '+': inc(i)
   elif s[i] == '-':
-    sign = -1.0
+    sign = true
     inc(i)
   if s[i] == 'N' or s[i] == 'n':
     if s[i+1] == 'A' or s[i+1] == 'a':
@@ -741,52 +745,41 @@ proc nimParseBiggestFloat(s: string, number: var BiggestFloat, start = 0): int {
     if s[i+1] == 'N' or s[i+1] == 'n':
       if s[i+2] == 'F' or s[i+2] == 'f':
         if s[i+3] notin IdentChars:
-          number = Inf*sign
+          number = if sign: -Inf else: Inf
           return i+3 - start
     return 0
-  while s[i] in {'0'..'9'}:
-    # Read integer part
-    flags = flags or 1
-    number = number * 10.0 + toFloat(ord(s[i]) - ord('0'))
+
+  var buf: string
+    # we could also use an `array[char, N]` buffer to avoid reallocs, or
+    # use a 2-pass algorithm that first computes the length.
+  if sign: buf.add '-'
+  template addInc =
+    buf.add s[i]
     inc(i)
+  template eatUnderscores =
     while s[i] == '_': inc(i)
-  # Decimal?
-  if s[i] == '.':
-    var hd = 1.0
+  while s[i] in {'0'..'9'}: # Read integer part
+    buf.add s[i]
     inc(i)
-    while s[i] in {'0'..'9'}:
-      # Read fractional part
-      flags = flags or 2
-      number = number * 10.0 + toFloat(ord(s[i]) - ord('0'))
-      hd = hd * 10.0
-      inc(i)
-      while s[i] == '_': inc(i)
-    number = number / hd # this complicated way preserves precision
+    eatUnderscores()
+  if s[i] == '.': # Decimal?
+    addInc()
+    while s[i] in {'0'..'9'}: # Read fractional part
+      addInc()
+      eatUnderscores()
   # Again, read integer and fractional part
-  if flags == 0: return 0
-  # Exponent?
-  if s[i] in {'e', 'E'}:
-    inc(i)
-    if s[i] == '+':
-      inc(i)
-    elif s[i] == '-':
-      esign = -1.0
-      inc(i)
-    if s[i] notin {'0'..'9'}:
-      return 0
+  if buf.len == ord(sign): return 0
+  if s[i] in {'e', 'E'}: # Exponent?
+    addInc()
+    if s[i] == '+': inc(i)
+    elif s[i] == '-': addInc()
+    if s[i] notin {'0'..'9'}: return 0
     while s[i] in {'0'..'9'}:
-      exponent = exponent * 10 + ord(s[i]) - ord('0')
-      inc(i)
-      while s[i] == '_': inc(i)
-  # Calculate Exponent
-  let hd = tenToThePowerOf(exponent)
-  if esign > 0.0: number = number * hd
-  else:           number = number / hd
-  # evaluate sign
-  number = number * sign
+      addInc()
+      eatUnderscores()
+  number = parseFloatNative(buf)
   result = i - start
 
-
 # Workaround for IE, IE up to version 11 lacks 'Math.trunc'. We produce
 # 'Math.trunc' for Nim's ``div`` and ``mod`` operators:
 const jsMathTrunc = """