* compiler/vmhooks: add getVar to allow vmops with var params * addFloat vmops with var param * cgen now renders float32 literals in c backend using roundtrip float to string
This commit is contained in:
parent
a8b3e7c059
commit
cf0cf32d27
21 changed files with 286 additions and 199 deletions
|
|
@ -1,5 +1,6 @@
|
|||
import std/private/digitsutils
|
||||
|
||||
import system/formatfloat
|
||||
export addFloat
|
||||
|
||||
proc `$`*(x: int): string {.magic: "IntToStr", noSideEffect.}
|
||||
## The stringify operator for an integer argument. Returns `x`
|
||||
|
|
@ -40,13 +41,9 @@ proc `$`*(x: int64): string {.magic: "Int64ToStr", noSideEffect.}
|
|||
## The stringify operator for an integer argument. Returns `x`
|
||||
## converted to a decimal string.
|
||||
|
||||
proc `$`*(x: float): string {.magic: "FloatToStr", noSideEffect.}
|
||||
## The stringify operator for a float argument. Returns `x`
|
||||
## converted to a decimal string.
|
||||
|
||||
proc `$`*(x: float32): string {.magic: "FloatToStr", noSideEffect.}
|
||||
## The stringify operator for a float32 argument. Returns `x`
|
||||
## converted to a decimal string.
|
||||
func `$`*(x: float | float32): string =
|
||||
## Outplace version of `addFloat`.
|
||||
result.addFloat(x)
|
||||
|
||||
proc `$`*(x: bool): string {.magic: "BoolToStr", noSideEffect.}
|
||||
## The stringify operator for a boolean argument. Returns `x`
|
||||
|
|
|
|||
|
|
@ -7,58 +7,126 @@
|
|||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
when defined(nimFpRoundtrips) and not defined(nimscript) and
|
||||
not defined(js) and defined(nimHasDragonBox):
|
||||
import dragonbox
|
||||
proc c_memcpy(a, b: pointer, size: csize_t): pointer {.importc: "memcpy", header: "<string.h>", discardable.}
|
||||
|
||||
proc writeFloatToBuffer*(buf: var array[65, char]; value: BiggestFloat): int =
|
||||
## This is the implementation to format floats.
|
||||
##
|
||||
## returns the amount of bytes written to `buf` not counting the
|
||||
## terminating '\0' character.
|
||||
result = toChars(buf, value, forceTrailingDotZero=true)
|
||||
buf[result] = '\0'
|
||||
proc addCstringN(result: var string, buf: cstring; buflen: int) =
|
||||
# no nimvm support needed, so it doesn't need to be fast here either
|
||||
let oldLen = result.len
|
||||
let newLen = oldLen + buflen
|
||||
result.setLen newLen
|
||||
c_memcpy(result[oldLen].addr, buf, buflen.csize_t)
|
||||
|
||||
else:
|
||||
proc c_sprintf(buf, frmt: cstring): cint {.header: "<stdio.h>",
|
||||
importc: "sprintf", varargs, noSideEffect.}
|
||||
import dragonbox, schubfach
|
||||
|
||||
proc writeToBuffer(buf: var array[65, char]; value: cstring) =
|
||||
var i = 0
|
||||
while value[i] != '\0':
|
||||
buf[i] = value[i]
|
||||
inc i
|
||||
proc writeFloatToBufferRoundtrip*(buf: var array[65, char]; value: BiggestFloat): int =
|
||||
## This is the implementation to format floats.
|
||||
##
|
||||
## returns the amount of bytes written to `buf` not counting the
|
||||
## terminating '\0' character.
|
||||
result = toChars(buf, value, forceTrailingDotZero=true)
|
||||
buf[result] = '\0'
|
||||
|
||||
proc writeFloatToBuffer*(buf: var array[65, char]; value: BiggestFloat): int =
|
||||
## This is the implementation to format floats.
|
||||
##
|
||||
## returns the amount of bytes written to `buf` not counting the
|
||||
## terminating '\0' character.
|
||||
var n: int = c_sprintf(addr buf, "%.16g", value)
|
||||
var hasDot = false
|
||||
for i in 0..n-1:
|
||||
if buf[i] == ',':
|
||||
buf[i] = '.'
|
||||
hasDot = true
|
||||
elif buf[i] in {'a'..'z', 'A'..'Z', '.'}:
|
||||
hasDot = true
|
||||
if not hasDot:
|
||||
buf[n] = '.'
|
||||
buf[n+1] = '0'
|
||||
buf[n+2] = '\0'
|
||||
result = n + 2
|
||||
proc writeFloatToBufferRoundtrip*(buf: var array[65, char]; value: float32): int =
|
||||
result = float32ToChars(buf, value, forceTrailingDotZero=true)
|
||||
buf[result] = '\0'
|
||||
|
||||
proc c_sprintf(buf, frmt: cstring): cint {.header: "<stdio.h>",
|
||||
importc: "sprintf", varargs, noSideEffect.}
|
||||
|
||||
proc writeToBuffer(buf: var array[65, char]; value: cstring) =
|
||||
var i = 0
|
||||
while value[i] != '\0':
|
||||
buf[i] = value[i]
|
||||
inc i
|
||||
|
||||
proc writeFloatToBufferSprintf*(buf: var array[65, char]; value: BiggestFloat): int =
|
||||
## This is the implementation to format floats.
|
||||
##
|
||||
## returns the amount of bytes written to `buf` not counting the
|
||||
## terminating '\0' character.
|
||||
var n: int = c_sprintf(addr buf, "%.16g", value)
|
||||
var hasDot = false
|
||||
for i in 0..n-1:
|
||||
if buf[i] == ',':
|
||||
buf[i] = '.'
|
||||
hasDot = true
|
||||
elif buf[i] in {'a'..'z', 'A'..'Z', '.'}:
|
||||
hasDot = true
|
||||
if not hasDot:
|
||||
buf[n] = '.'
|
||||
buf[n+1] = '0'
|
||||
buf[n+2] = '\0'
|
||||
result = n + 2
|
||||
else:
|
||||
result = n
|
||||
# On Windows nice numbers like '1.#INF', '-1.#INF' or '1.#NAN' or 'nan(ind)'
|
||||
# of '-1.#IND' are produced.
|
||||
# We want to get rid of these here:
|
||||
if buf[n-1] in {'n', 'N', 'D', 'd', ')'}:
|
||||
writeToBuffer(buf, "nan")
|
||||
result = 3
|
||||
elif buf[n-1] == 'F':
|
||||
if buf[0] == '-':
|
||||
writeToBuffer(buf, "-inf")
|
||||
result = 4
|
||||
else:
|
||||
result = n
|
||||
# On Windows nice numbers like '1.#INF', '-1.#INF' or '1.#NAN' or 'nan(ind)'
|
||||
# of '-1.#IND' are produced.
|
||||
# We want to get rid of these here:
|
||||
if buf[n-1] in {'n', 'N', 'D', 'd', ')'}:
|
||||
writeToBuffer(buf, "nan")
|
||||
writeToBuffer(buf, "inf")
|
||||
result = 3
|
||||
elif buf[n-1] == 'F':
|
||||
if buf[0] == '-':
|
||||
writeToBuffer(buf, "-inf")
|
||||
result = 4
|
||||
else:
|
||||
writeToBuffer(buf, "inf")
|
||||
result = 3
|
||||
|
||||
proc writeFloatToBuffer*(buf: var array[65, char]; value: BiggestFloat | float32): int {.inline.} =
|
||||
when defined(nimFpRoundtrips):
|
||||
writeFloatToBufferRoundtrip(buf, value)
|
||||
else:
|
||||
writeFloatToBufferSprintf(buf, value)
|
||||
|
||||
proc addFloatRoundtrip*(result: var string; x: float | float32) =
|
||||
when nimvm:
|
||||
doAssert false
|
||||
else:
|
||||
var buffer {.noinit.}: array[65, char]
|
||||
let n = writeFloatToBufferRoundtrip(buffer, x)
|
||||
result.addCstringN(cstring(buffer[0].addr), n)
|
||||
|
||||
proc addFloatSprintf*(result: var string; x: float) =
|
||||
when nimvm:
|
||||
doAssert false
|
||||
else:
|
||||
var buffer {.noinit.}: array[65, char]
|
||||
let n = writeFloatToBufferSprintf(buffer, x)
|
||||
result.addCstringN(cstring(buffer[0].addr), n)
|
||||
|
||||
proc nimFloatToString(a: float): cstring =
|
||||
## ensures the result doesn't print like an integer, i.e. return 2.0, not 2
|
||||
# print `-0.0` properly
|
||||
asm """
|
||||
function nimOnlyDigitsOrMinus(n) {
|
||||
return n.toString().match(/^-?\d+$/);
|
||||
}
|
||||
if (Number.isSafeInteger(`a`))
|
||||
`result` = `a` === 0 && 1 / `a` < 0 ? "-0.0" : `a`+".0"
|
||||
else {
|
||||
`result` = `a`+""
|
||||
if(nimOnlyDigitsOrMinus(`result`)){
|
||||
`result` = `a`+".0"
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
proc addFloat*(result: var string; x: float | float32) {.inline.} =
|
||||
## Converts float to its string representation and appends it to `result`.
|
||||
runnableExamples:
|
||||
var
|
||||
s = "foo:"
|
||||
b = 45.67
|
||||
s.addFloat(45.67)
|
||||
assert s == "foo:45.67"
|
||||
template impl =
|
||||
when defined(nimFpRoundtrips):
|
||||
addFloatRoundtrip(result, x)
|
||||
else:
|
||||
addFloatSprintf(result, x)
|
||||
when defined(js):
|
||||
when nimvm: impl()
|
||||
else:
|
||||
result.add nimFloatToString(x)
|
||||
else: impl()
|
||||
|
|
|
|||
|
|
@ -496,23 +496,6 @@ proc negInt(a: int): int {.compilerproc.} =
|
|||
proc negInt64(a: int64): int64 {.compilerproc.} =
|
||||
result = a*(-1)
|
||||
|
||||
proc nimFloatToString(a: float): cstring {.compilerproc.} =
|
||||
## ensures the result doesn't print like an integer, i.e. return 2.0, not 2
|
||||
# print `-0.0` properly
|
||||
asm """
|
||||
function nimOnlyDigitsOrMinus(n) {
|
||||
return n.toString().match(/^-?\d+$/);
|
||||
}
|
||||
if (Number.isSafeInteger(`a`))
|
||||
`result` = `a` === 0 && 1 / `a` < 0 ? "-0.0" : `a`+".0"
|
||||
else {
|
||||
`result` = `a`+""
|
||||
if(nimOnlyDigitsOrMinus(`result`)){
|
||||
`result` = `a`+".0"
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
proc absInt(a: int): int {.compilerproc.} =
|
||||
result = if a < 0: a*(-1) else: a
|
||||
|
||||
|
|
@ -703,6 +686,7 @@ proc addChar(x: string, c: char) {.compilerproc, asmNoStackFrame.} =
|
|||
{.pop.}
|
||||
|
||||
proc tenToThePowerOf(b: int): BiggestFloat =
|
||||
# xxx deadcode
|
||||
var b = b
|
||||
var a = 10.0
|
||||
result = 1.0
|
||||
|
|
|
|||
|
|
@ -19,9 +19,9 @@ proc repr*(x: uint64): string {.noSideEffect.} =
|
|||
## converted to a decimal string.
|
||||
$x #Calls `$` from system/strmantle.nim
|
||||
|
||||
proc repr*(x: float): string {.magic: "FloatToStr", noSideEffect.}
|
||||
## repr for a float argument. Returns `x`
|
||||
## converted to a decimal string.
|
||||
proc repr*(x: float): string =
|
||||
## Same as $x
|
||||
$x
|
||||
|
||||
proc repr*(x: bool): string {.magic: "BoolToStr", noSideEffect.}
|
||||
## repr for a boolean argument. Returns `x`
|
||||
|
|
|
|||
|
|
@ -69,47 +69,6 @@ proc nimIntToStr(x: int): string {.compilerRtl.} =
|
|||
result = newStringOfCap(sizeof(x)*4)
|
||||
result.addInt x
|
||||
|
||||
proc addCstringN(result: var string, buf: cstring; buflen: int) =
|
||||
# no nimvm support needed, so it doesn't need to be fast here either
|
||||
let oldLen = result.len
|
||||
let newLen = oldLen + buflen
|
||||
result.setLen newLen
|
||||
copyMem(result[oldLen].addr, buf, buflen)
|
||||
|
||||
import formatfloat
|
||||
|
||||
proc addFloat*(result: var string; x: float) =
|
||||
## Converts float to its string representation and appends it to `result`.
|
||||
##
|
||||
## .. code-block:: Nim
|
||||
## var
|
||||
## a = "123"
|
||||
## b = 45.67
|
||||
## a.addFloat(b) # a <- "12345.67"
|
||||
when nimvm:
|
||||
result.add $x
|
||||
else:
|
||||
var buffer {.noinit.}: array[65, char]
|
||||
let n = writeFloatToBuffer(buffer, x)
|
||||
result.addCstringN(cstring(buffer[0].addr), n)
|
||||
|
||||
proc nimFloatToStr(f: float): string {.compilerproc.} =
|
||||
result = newStringOfCap(8)
|
||||
result.addFloat f
|
||||
|
||||
when defined(nimFpRoundtrips) and not defined(nimscript) and
|
||||
not defined(js) and defined(nimHasDragonBox):
|
||||
import schubfach
|
||||
|
||||
proc nimFloat32ToStr(f: float32): string {.compilerproc.} =
|
||||
when declared(float32ToChars):
|
||||
result = newString(65)
|
||||
let L = float32ToChars(result, f, forceTrailingDotZero=true)
|
||||
setLen(result, L)
|
||||
else:
|
||||
result = newStringOfCap(8)
|
||||
result.addFloat f
|
||||
|
||||
proc c_strtod(buf: cstring, endptr: ptr cstring): float64 {.
|
||||
importc: "strtod", header: "<stdlib.h>", noSideEffect.}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue