fixes #11012
This commit is contained in:
parent
499fa3f3dc
commit
59ccaa43c7
3 changed files with 28 additions and 50 deletions
|
|
@ -102,7 +102,9 @@ of ``formatValue`` procs. The required signature for a type ``T`` that supports
|
||||||
formatting is usually ``proc formatValue(result: var string; x: T; specifier: string)``.
|
formatting is usually ``proc formatValue(result: var string; x: T; specifier: string)``.
|
||||||
|
|
||||||
The subexpression after the colon
|
The subexpression after the colon
|
||||||
(``arg`` in ``&"{key} is {value:arg} {{z}}"``) is optional. It will be passed as the last argument to ``formatValue``. When the colon with the subexpression it is left out, an empty string will be taken instead.
|
(``arg`` in ``&"{key} is {value:arg} {{z}}"``) is optional. It will be passed as
|
||||||
|
the last argument to ``formatValue``. When the colon with the subexpression it is
|
||||||
|
left out, an empty string will be taken instead.
|
||||||
|
|
||||||
For strings and numeric types the optional argument is a so-called
|
For strings and numeric types the optional argument is a so-called
|
||||||
"standard format specifier".
|
"standard format specifier".
|
||||||
|
|
@ -215,8 +217,7 @@ Limitations
|
||||||
===========
|
===========
|
||||||
|
|
||||||
Because of the well defined order how templates and macros are
|
Because of the well defined order how templates and macros are
|
||||||
expanded, strformat cannot expand template arguments.
|
expanded, strformat cannot expand template arguments:
|
||||||
|
|
||||||
|
|
||||||
.. code-block:: nim
|
.. code-block:: nim
|
||||||
template myTemplate(arg: untyped): untyped =
|
template myTemplate(arg: untyped): untyped =
|
||||||
|
|
@ -233,27 +234,6 @@ quoted string literal. It is not an identifier yet. Then the strformat
|
||||||
macro creates the ``arg`` identifier from the string literal. An
|
macro creates the ``arg`` identifier from the string literal. An
|
||||||
identifier that cannot be resolved anymore.
|
identifier that cannot be resolved anymore.
|
||||||
|
|
||||||
.. code-block:: nim
|
|
||||||
let x = "abc"
|
|
||||||
myTemplate(x)
|
|
||||||
|
|
||||||
# expansion of myTemplate
|
|
||||||
|
|
||||||
let x = "abc"
|
|
||||||
echo "arg is: ", x
|
|
||||||
echo &"--- {arg} ---"
|
|
||||||
|
|
||||||
# expansion of `&`
|
|
||||||
|
|
||||||
let x = "abc"
|
|
||||||
echo "arg is: ", x
|
|
||||||
echo:
|
|
||||||
var temp = newStringOfCap(20)
|
|
||||||
temp.add "--- "
|
|
||||||
temp.formatValue arg, "" # arg cannot be resolved anymore
|
|
||||||
temp.add " ---"
|
|
||||||
temp
|
|
||||||
|
|
||||||
The workaround for this is to bind template argument to a new local variable.
|
The workaround for this is to bind template argument to a new local variable.
|
||||||
|
|
||||||
.. code-block:: nim
|
.. code-block:: nim
|
||||||
|
|
@ -265,11 +245,12 @@ The workaround for this is to bind template argument to a new local variable.
|
||||||
echo &"--- {arg1} ---"
|
echo &"--- {arg1} ---"
|
||||||
|
|
||||||
The use of ``{.inject.}`` here is necessary again because of template
|
The use of ``{.inject.}`` here is necessary again because of template
|
||||||
expansion order and hygienic templates. But since we generelly want to
|
expansion order and hygienic templates. But since we generally want to
|
||||||
keep the hygienicness of ``myTemplate``, and we do not want ``arg1``
|
keep the hygienicness of ``myTemplate``, and we do not want ``arg1``
|
||||||
to be injected into the context where ``myTemplate`` is expanded,
|
to be injected into the context where ``myTemplate`` is expanded,
|
||||||
everything is wrapped in a ``block``.
|
everything is wrapped in a ``block``.
|
||||||
|
|
||||||
|
|
||||||
Future directions
|
Future directions
|
||||||
=================
|
=================
|
||||||
|
|
||||||
|
|
@ -522,8 +503,9 @@ proc formatValue*(result: var string; value: string; specifier: string) =
|
||||||
setLen(value, runeOffset(value, spec.precision))
|
setLen(value, runeOffset(value, spec.precision))
|
||||||
result.add alignString(value, spec.minimumWidth, spec.align, spec.fill)
|
result.add alignString(value, spec.minimumWidth, spec.align, spec.fill)
|
||||||
|
|
||||||
template formatValue[T: enum](result: var string; value: T; specifier: string) =
|
proc formatValue[T](result: var string; value: T; specifier: string) =
|
||||||
result.add $value
|
mixin `$`
|
||||||
|
formatValue(result, $value, specifier)
|
||||||
|
|
||||||
template formatValue(result: var string; value: char; specifier: string) =
|
template formatValue(result: var string; value: char; specifier: string) =
|
||||||
result.add value
|
result.add value
|
||||||
|
|
@ -531,7 +513,7 @@ template formatValue(result: var string; value: char; specifier: string) =
|
||||||
template formatValue(result: var string; value: cstring; specifier: string) =
|
template formatValue(result: var string; value: cstring; specifier: string) =
|
||||||
result.add value
|
result.add value
|
||||||
|
|
||||||
proc formatValue[T](result: var string; value: openarray[T]; specifier: string) =
|
proc formatValue(result: var string; value: (array|seq|openArray); specifier: string) =
|
||||||
result.add "["
|
result.add "["
|
||||||
for i, it in value:
|
for i, it in value:
|
||||||
if i != 0:
|
if i != 0:
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
discard """
|
discard """
|
||||||
action: "run"
|
action: "run"
|
||||||
|
output: '''Received (name: "Foo", species: "Bar")'''
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import strformat
|
import strformat
|
||||||
|
|
@ -64,16 +65,14 @@ doAssert fmt"{0.0: g}" == " 0"
|
||||||
let data1 = [1'i64, 10000'i64, 10000000'i64]
|
let data1 = [1'i64, 10000'i64, 10000000'i64]
|
||||||
let data2 = [10000000'i64, 100'i64, 1'i64]
|
let data2 = [10000000'i64, 100'i64, 1'i64]
|
||||||
|
|
||||||
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] ="
|
||||||
|
|
||||||
# custom format Value
|
# custom format Value
|
||||||
|
|
||||||
type
|
type
|
||||||
Vec2[T] = object
|
Vec2[T] = object
|
||||||
x,y: T
|
x,y: T
|
||||||
Vec2f = Vec2[float32]
|
|
||||||
Vec2i = Vec2[int32]
|
|
||||||
|
|
||||||
proc formatValue[T](result: var string; value: Vec2[T]; specifier: string) =
|
proc formatValue[T](result: var string; value: Vec2[T]; specifier: string) =
|
||||||
result.add '['
|
result.add '['
|
||||||
|
|
@ -82,8 +81,8 @@ proc formatValue[T](result: var string; value: Vec2[T]; specifier: string) =
|
||||||
result.formatValue value.y, specifier
|
result.formatValue value.y, specifier
|
||||||
result.add "]"
|
result.add "]"
|
||||||
|
|
||||||
let v1 = Vec2f(x:1.0, y: 2.0)
|
let v1 = Vec2[float32](x:1.0, y: 2.0)
|
||||||
let v2 = Vec2i(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]"
|
||||||
|
|
||||||
# issue #7632
|
# issue #7632
|
||||||
|
|
@ -94,3 +93,16 @@ doAssert works(5) == "formatted 5"
|
||||||
doAssert fails0(6) == "formatted 6"
|
doAssert fails0(6) == "formatted 6"
|
||||||
doAssert fails(7) == "formatted 7"
|
doAssert fails(7) == "formatted 7"
|
||||||
doAssert fails2[0](8) == "formatted 8"
|
doAssert fails2[0](8) == "formatted 8"
|
||||||
|
|
||||||
|
|
||||||
|
# bug #11012
|
||||||
|
|
||||||
|
type
|
||||||
|
Animal = object
|
||||||
|
name, species: string
|
||||||
|
AnimalRef = ref Animal
|
||||||
|
|
||||||
|
proc print_object(animalAddr: AnimalRef) =
|
||||||
|
echo fmt"Received {animalAddr[]}"
|
||||||
|
|
||||||
|
print_object(AnimalRef(name: "Foo", species: "Bar"))
|
||||||
|
|
|
||||||
|
|
@ -1,16 +0,0 @@
|
||||||
discard """
|
|
||||||
errormsg: '''type mismatch: got <string, Obj, string>'''
|
|
||||||
nimout: '''proc formatValue'''
|
|
||||||
"""
|
|
||||||
|
|
||||||
# This test is here to make sure that there is a clean error that
|
|
||||||
# that indicates ``formatValue`` needs to be overloaded with the custom type.
|
|
||||||
|
|
||||||
import strformat
|
|
||||||
|
|
||||||
type Obj = object
|
|
||||||
|
|
||||||
proc `$`(o: Obj): string = "foobar"
|
|
||||||
|
|
||||||
var o: Obj
|
|
||||||
doAssert fmt"{o}" == "foobar"
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue