mirror of
https://github.com/nim-lang/Nim.git
synced 2025-12-28 17:04:41 +00:00
fixes #18134; registers formatBiggestFloat in vmops strformat supports float format in VM
This commit is contained in:
@@ -36,7 +36,9 @@ from std/osproc import nil
|
||||
when defined(nimPreviewSlimSystem):
|
||||
import std/syncio
|
||||
else:
|
||||
from std/formatfloat import addFloatRoundtrip, addFloatSprintf
|
||||
from std/formatfloat import addFloatRoundtrip, addFloatSprintf
|
||||
|
||||
from std/strutils import formatBiggestFloat, FloatFormatMode
|
||||
|
||||
# There are some useful procs in vmconv.
|
||||
import vmconv, vmmarshal
|
||||
@@ -374,6 +376,10 @@ proc registerAdditionalOps*(c: PCtx) =
|
||||
let x = a.getFloat(1)
|
||||
addFloatSprintf(p.strVal, x)
|
||||
|
||||
registerCallback c, "stdlib.strutils.formatBiggestFloat", proc(a: VmArgs) =
|
||||
setResult(a, formatBiggestFloat(a.getFloat(0), FloatFormatMode(a.getInt(1)),
|
||||
a.getInt(2), chr(a.getInt(3))))
|
||||
|
||||
wrapIterator("stdlib.envvars.envPairsImplSeq"): envPairs()
|
||||
|
||||
registerCallback c, "stdlib.marshal.toVM", proc(a: VmArgs) =
|
||||
|
||||
@@ -2413,60 +2413,63 @@ func formatBiggestFloat*(f: BiggestFloat, format: FloatFormatMode = ffDefault,
|
||||
doAssert x.formatBiggestFloat() == "123.4560000000000"
|
||||
doAssert x.formatBiggestFloat(ffDecimal, 4) == "123.4560"
|
||||
doAssert x.formatBiggestFloat(ffScientific, 2) == "1.23e+02"
|
||||
when defined(js):
|
||||
var precision = precision
|
||||
if precision == -1:
|
||||
# use the same default precision as c_sprintf
|
||||
precision = 6
|
||||
var res: cstring
|
||||
case format
|
||||
of ffDefault:
|
||||
{.emit: "`res` = `f`.toString();".}
|
||||
of ffDecimal:
|
||||
{.emit: "`res` = `f`.toFixed(`precision`);".}
|
||||
of ffScientific:
|
||||
{.emit: "`res` = `f`.toExponential(`precision`);".}
|
||||
result = $res
|
||||
if 1.0 / f == -Inf:
|
||||
# JavaScript removes the "-" from negative Zero, add it back here
|
||||
result = "-" & $res
|
||||
for i in 0 ..< result.len:
|
||||
# Depending on the locale either dot or comma is produced,
|
||||
# but nothing else is possible:
|
||||
if result[i] in {'.', ','}: result[i] = decimalSep
|
||||
when nimvm:
|
||||
discard "implemented in the vmops"
|
||||
else:
|
||||
const floatFormatToChar: array[FloatFormatMode, char] = ['g', 'f', 'e']
|
||||
var
|
||||
frmtstr {.noinit.}: array[0..5, char]
|
||||
buf {.noinit.}: array[0..2500, char]
|
||||
L: cint
|
||||
frmtstr[0] = '%'
|
||||
if precision >= 0:
|
||||
frmtstr[1] = '#'
|
||||
frmtstr[2] = '.'
|
||||
frmtstr[3] = '*'
|
||||
frmtstr[4] = floatFormatToChar[format]
|
||||
frmtstr[5] = '\0'
|
||||
L = c_sprintf(cast[cstring](addr buf), cast[cstring](addr frmtstr), precision, f)
|
||||
when defined(js):
|
||||
var precision = precision
|
||||
if precision == -1:
|
||||
# use the same default precision as c_sprintf
|
||||
precision = 6
|
||||
var res: cstring
|
||||
case format
|
||||
of ffDefault:
|
||||
{.emit: "`res` = `f`.toString();".}
|
||||
of ffDecimal:
|
||||
{.emit: "`res` = `f`.toFixed(`precision`);".}
|
||||
of ffScientific:
|
||||
{.emit: "`res` = `f`.toExponential(`precision`);".}
|
||||
result = $res
|
||||
if 1.0 / f == -Inf:
|
||||
# JavaScript removes the "-" from negative Zero, add it back here
|
||||
result = "-" & $res
|
||||
for i in 0 ..< result.len:
|
||||
# Depending on the locale either dot or comma is produced,
|
||||
# but nothing else is possible:
|
||||
if result[i] in {'.', ','}: result[i] = decimalSep
|
||||
else:
|
||||
frmtstr[1] = floatFormatToChar[format]
|
||||
frmtstr[2] = '\0'
|
||||
L = c_sprintf(cast[cstring](addr buf), cast[cstring](addr frmtstr), f)
|
||||
result = newString(L)
|
||||
for i in 0 ..< L:
|
||||
# Depending on the locale either dot or comma is produced,
|
||||
# but nothing else is possible:
|
||||
if buf[i] in {'.', ','}: result[i] = decimalSep
|
||||
else: result[i] = buf[i]
|
||||
when defined(windows):
|
||||
# VS pre 2015 violates the C standard: "The exponent always contains at
|
||||
# least two digits, and only as many more digits as necessary to
|
||||
# represent the exponent." [C11 §7.21.6.1]
|
||||
# The following post-processing fixes this behavior.
|
||||
if result.len > 4 and result[^4] == '+' and result[^3] == '0':
|
||||
result[^3] = result[^2]
|
||||
result[^2] = result[^1]
|
||||
result.setLen(result.len - 1)
|
||||
const floatFormatToChar: array[FloatFormatMode, char] = ['g', 'f', 'e']
|
||||
var
|
||||
frmtstr {.noinit.}: array[0..5, char]
|
||||
buf {.noinit.}: array[0..2500, char]
|
||||
L: cint
|
||||
frmtstr[0] = '%'
|
||||
if precision >= 0:
|
||||
frmtstr[1] = '#'
|
||||
frmtstr[2] = '.'
|
||||
frmtstr[3] = '*'
|
||||
frmtstr[4] = floatFormatToChar[format]
|
||||
frmtstr[5] = '\0'
|
||||
L = c_sprintf(cast[cstring](addr buf), cast[cstring](addr frmtstr), precision, f)
|
||||
else:
|
||||
frmtstr[1] = floatFormatToChar[format]
|
||||
frmtstr[2] = '\0'
|
||||
L = c_sprintf(cast[cstring](addr buf), cast[cstring](addr frmtstr), f)
|
||||
result = newString(L)
|
||||
for i in 0 ..< L:
|
||||
# Depending on the locale either dot or comma is produced,
|
||||
# but nothing else is possible:
|
||||
if buf[i] in {'.', ','}: result[i] = decimalSep
|
||||
else: result[i] = buf[i]
|
||||
when defined(windows):
|
||||
# VS pre 2015 violates the C standard: "The exponent always contains at
|
||||
# least two digits, and only as many more digits as necessary to
|
||||
# represent the exponent." [C11 §7.21.6.1]
|
||||
# The following post-processing fixes this behavior.
|
||||
if result.len > 4 and result[^4] == '+' and result[^3] == '0':
|
||||
result[^3] = result[^2]
|
||||
result[^2] = result[^1]
|
||||
result.setLen(result.len - 1)
|
||||
|
||||
func formatFloat*(f: float, format: FloatFormatMode = ffDefault,
|
||||
precision: range[-1..32] = 16; decimalSep = '.'): string {.
|
||||
|
||||
@@ -475,15 +475,17 @@ proc main() =
|
||||
|
||||
# Note: times.format adheres to the format protocol. Test that this
|
||||
# works:
|
||||
when nimvm:
|
||||
discard
|
||||
else:
|
||||
var dt = dateTime(2000, mJan, 01, 00, 00, 00)
|
||||
check &"{dt:yyyy-MM-dd}", "2000-01-01"
|
||||
|
||||
var dt = initDateTime(01, mJan, 2000, 00, 00, 00)
|
||||
check &"{dt:yyyy-MM-dd}", "2000-01-01"
|
||||
var tm = fromUnix(0)
|
||||
discard &"{tm}"
|
||||
|
||||
var tm = fromUnix(0)
|
||||
discard &"{tm}"
|
||||
|
||||
var noww = now()
|
||||
check &"{noww}", $noww
|
||||
var noww = now()
|
||||
check &"{noww}", $noww
|
||||
|
||||
# Unicode string tests
|
||||
check &"""{"αβγ"}""", "αβγ"
|
||||
@@ -558,5 +560,6 @@ proc main() =
|
||||
doAssert &"""{(if true: "'" & "'" & ')' else: "")}""" == "'')"
|
||||
doAssert &"{(if true: \"\'\" & \"'\" & ')' else: \"\")}" == "'')"
|
||||
doAssert fmt"""{(if true: "'" & ')' else: "")}""" == "')"
|
||||
# xxx static: main()
|
||||
|
||||
static: main()
|
||||
main()
|
||||
|
||||
Reference in New Issue
Block a user