add debug fmt string like python's (#14808)

* add debug format string

* remove try except

* add changelog
This commit is contained in:
flywind 2020-06-30 21:21:37 +08:00 • committed by GitHub
commit 8be54b8fa7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 119 additions and 2 deletions

View file

@ -117,6 +117,8 @@
- Add `typetraits.elementType` to get element type of an iterable. - Add `typetraits.elementType` to get element type of an iterable.
- `typetraits.$`: `$(int,)` is now `"(int,)"`; `$tuple[]` is now `"tuple[]"` - `typetraits.$`: `$(int,)` is now `"(int,)"`; `$tuple[]` is now `"tuple[]"`
- `strformat.fmt` and `strformat.&` support `= specifier`. `fmt"{expr=}"` now expands to `fmt"expr={expr}"`.
## Language changes ## Language changes
- In the newruntime it is now allowed to assign to the discriminator field - In the newruntime it is now allowed to assign to the discriminator field
without restrictions as long as case object doesn't have custom destructor. without restrictions as long as case object doesn't have custom destructor.

View file

@ -552,8 +552,18 @@ proc strformatImpl(pattern: NimNode; openChar, closeChar: char): NimNode =
var subexpr = "" var subexpr = ""
while i < f.len and f[i] != closeChar and f[i] != ':': while i < f.len and f[i] != closeChar and f[i] != ':':
if f[i] == '=':
let start = i
inc i
i += f.skipWhitespace(i)
if f[i] == closeChar or f[i] == ':':
result.add newCall(bindSym"add", res, newLit(subexpr & f[start ..< i]))
else:
subexpr.add f[start ..< i]
else:
subexpr.add f[i] subexpr.add f[i]
inc i inc i
var x: NimNode var x: NimNode
try: try:
x = parseExpr(subexpr) x = parseExpr(subexpr)

View file

@ -6,6 +6,8 @@ output: '''Received (name: "Foo", species: "Bar")'''
# issue #7632 # issue #7632
import genericstrformat import genericstrformat
import strutils
doAssert works(5) == "formatted 5" doAssert works(5) == "formatted 5"
doAssert fails0(6) == "formatted 6" doAssert fails0(6) == "formatted 6"
@ -86,6 +88,8 @@ proc formatValue(result: var string; value: (array|seq|openArray); specifier: st
doAssert fmt"data1: {data1:8} #" == "data1: [ 1, 10000, 10000000] #" doAssert fmt"data1: {data1:8} #" == "data1: [ 1, 10000, 10000000] #"
doAssert fmt"data2: {data2:8} =" == "data2: [10000000, 100, 1] =" doAssert fmt"data2: {data2:8} =" == "data2: [10000000, 100, 1] ="
doAssert fmt"data1: {data1=:8} #" == "data1: data1=[ 1, 10000, 10000000] #"
doAssert fmt"data2: {data2=:8} =" == "data2: data2=[10000000, 100, 1] ="
# custom format Value # custom format Value
@ -103,6 +107,7 @@ proc formatValue[T](result: var string; value: Vec2[T]; specifier: string) =
let v1 = Vec2[float32](x:1.0, y: 2.0) let v1 = Vec2[float32](x:1.0, y: 2.0)
let v2 = Vec2[int32](x:1, y: 1337) let v2 = Vec2[int32](x:1, y: 1337)
doAssert fmt"v1: {v1:+08} v2: {v2:>4}" == "v1: [+0000001, +0000002] v2: [ 1, 1337]" doAssert fmt"v1: {v1:+08} v2: {v2:>4}" == "v1: [+0000001, +0000002] v2: [ 1, 1337]"
doAssert fmt"v1: {v1=:+08} v2: {v2=:>4}" == "v1: v1=[+0000001, +0000002] v2: v2=[ 1, 1337]"
# bug #11012 # bug #11012
@ -126,6 +131,14 @@ doAssert fmt"{pos:3o}" == "100"
doAssert fmt"{pos:3x}" == " 40" doAssert fmt"{pos:3x}" == " 40"
doAssert fmt"{pos:3X}" == " 40" doAssert fmt"{pos:3X}" == " 40"
doAssert fmt"{pos=:3}" == "pos= 64"
doAssert fmt"{pos=:3b}" == "pos=1000000"
doAssert fmt"{pos=:3d}" == "pos= 64"
doAssert fmt"{pos=:3o}" == "pos=100"
doAssert fmt"{pos=:3x}" == "pos= 40"
doAssert fmt"{pos=:3X}" == "pos= 40"
let nat: Natural = 64 let nat: Natural = 64
doAssert fmt"{nat:3}" == " 64" doAssert fmt"{nat:3}" == " 64"
doAssert fmt"{nat:3b}" == "1000000" doAssert fmt"{nat:3b}" == "1000000"
@ -134,6 +147,13 @@ doAssert fmt"{nat:3o}" == "100"
doAssert fmt"{nat:3x}" == " 40" doAssert fmt"{nat:3x}" == " 40"
doAssert fmt"{nat:3X}" == " 40" doAssert fmt"{nat:3X}" == " 40"
doAssert fmt"{nat=:3}" == "nat= 64"
doAssert fmt"{nat=:3b}" == "nat=1000000"
doAssert fmt"{nat=:3d}" == "nat= 64"
doAssert fmt"{nat=:3o}" == "nat=100"
doAssert fmt"{nat=:3x}" == "nat= 40"
doAssert fmt"{nat=:3X}" == "nat= 40"
# bug #12612 # bug #12612
proc my_proc = proc my_proc =
const value = "value" const value = "value"
@ -186,6 +206,14 @@ doAssert fmt"{msg}{'\n'}" == "hello\n"
doAssert fmt("{msg}\n") == "hello\n" doAssert fmt("{msg}\n") == "hello\n"
doAssert "{msg}\n".fmt == "hello\n" doAssert "{msg}\n".fmt == "hello\n"
doAssert fmt"{msg=}\n" == "msg=hello\\n"
doAssert &"{msg=}\n" == "msg=hello\n"
doAssert fmt"{msg=}{'\n'}" == "msg=hello\n"
doAssert fmt("{msg=}\n") == "msg=hello\n"
doAssert "{msg=}\n".fmt == "msg=hello\n"
doAssert &"""{"abc":>4}""" == " abc" doAssert &"""{"abc":>4}""" == " abc"
doAssert &"""{"abc":<4}""" == "abc " doAssert &"""{"abc":<4}""" == "abc "
@ -204,3 +232,80 @@ doAssert fmt"{123.456:<9.4f}" == "123.4560 "
doAssert fmt"{123.456:e}" == "1.234560e+02" doAssert fmt"{123.456:e}" == "1.234560e+02"
doAssert fmt"{123.456:>13e}" == " 1.234560e+02" doAssert fmt"{123.456:>13e}" == " 1.234560e+02"
doAssert fmt"{123.456:13e}" == " 1.234560e+02" doAssert fmt"{123.456:13e}" == " 1.234560e+02"
doAssert &"""{"abc"=:>4}""" == "\"abc\"= abc"
doAssert &"""{"abc"=:<4}""" == "\"abc\"=abc "
doAssert fmt"{-12345=:08}" == "-12345=-0012345"
doAssert fmt"{-1=:3}" == "-1= -1"
doAssert fmt"{-1=:03}" == "-1=-01"
doAssert fmt"{16=:#X}" == "16=0x10"
doAssert fmt"{123.456=}" == "123.456=123.456"
doAssert fmt"{123.456=:>9.3f}" == "123.456= 123.456"
doAssert fmt"{123.456=:9.3f}" == "123.456= 123.456"
doAssert fmt"{123.456=:9.4f}" == "123.456= 123.4560"
doAssert fmt"{123.456=:>9.0f}" == "123.456= 123."
doAssert fmt"{123.456=:<9.4f}" == "123.456=123.4560 "
doAssert fmt"{123.456=:e}" == "123.456=1.234560e+02"
doAssert fmt"{123.456=:>13e}" == "123.456= 1.234560e+02"
doAssert fmt"{123.456=:13e}" == "123.456= 1.234560e+02"
## tests for debug format string
block:
var name = "hello"
let age = 21
const hobby = "swim"
doAssert fmt"{age*9 + 16=}" == "age*9 + 16=205"
doAssert &"name: {name =}\nage: { age =: >7}\nhobby: { hobby= : 8}" ==
"name: name =hello\nage: age = 21\nhobby: hobby= swim "
doAssert fmt"{age == 12}" == "false"
doAssert fmt"{name.toUpperAscii( ) = }" == "name.toUpperAscii( ) = HELLO"
doAssert fmt"{ toUpperAscii( s = name ) = }" == " toUpperAscii( s = name ) = HELLO"
doAssert fmt"{ strutils.toUpperAscii( s = name ) = }" == " strutils.toUpperAscii( s = name ) = HELLO"
doAssert fmt"{age==12}" == "false"
doAssert fmt"{age!= 12}" == "true"
doAssert fmt"{age <= 12}" == "false"
for i in 1 .. 10:
doAssert fmt"{age.float =: .2f}" == "age.float = 21.00"
doAssert fmt"{age.float() =:.3f}" == "age.float() =21.000"
doAssert fmt"{float age= :.3f}" == "float age= 21.000"
doAssert fmt"{12 == int(`!=`(age, 12))}" == "false"
doAssert fmt"{0==1}" == "false"
block:
let x = "hello"
doAssert fmt"{x=}" == "x=" & $x
doAssert fmt"{x =}" == "x =" & $x
let y = 3.1415926
doAssert fmt"{y=:.2f}" == fmt"y={y:.2f}"
doAssert fmt"{y=}" == fmt"y={y}"
doAssert fmt"{y =: <16}" == fmt"y ={y: <16}"
proc hello(a: string, b: float): int = 12
template foo(a: string, b: float): int = 18
doAssert fmt"{hello(x, y)=}" == "hello(x, y)=12"
doAssert fmt"{hello(x, y) =}" == "hello(x, y) =12"
doAssert fmt"{hello(x, y)= }" == "hello(x, y)= 12"
doAssert fmt"{hello(x, y) = }" == "hello(x, y) = 12"
doAssert fmt"{x.hello(y)=}" == "x.hello(y)=12"
doAssert fmt"{x.hello(y) =}" == "x.hello(y) =12"
doAssert fmt"{x.hello(y)= }" == "x.hello(y)= 12"
doAssert fmt"{x.hello(y) = }" == "x.hello(y) = 12"
doAssert fmt"{foo(x, y)=}" == "foo(x, y)=18"
doAssert fmt"{foo(x, y) =}" == "foo(x, y) =18"
doAssert fmt"{foo(x, y)= }" == "foo(x, y)= 18"
doAssert fmt"{foo(x, y) = }" == "foo(x, y) = 18"
doAssert fmt"{x.foo(y)=}" == "x.foo(y)=18"
doAssert fmt"{x.foo(y) =}" == "x.foo(y) =18"
doAssert fmt"{x.foo(y)= }" == "x.foo(y)= 18"
doAssert fmt"{x.foo(y) = }" == "x.foo(y) = 18"