Skip to content

Commit

Permalink
add extractGeneric: extractGeneric(Foo2[float, string], 0) is float
Browse files Browse the repository at this point in the history
  • Loading branch information
timotheecour committed Aug 7, 2018
1 parent bbc404d commit 1c669ab
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 1 deletion.
3 changes: 2 additions & 1 deletion doc/manual.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4351,14 +4351,15 @@ type classes are called `bind many`:idx: types.

Procs written with the implicitly generic style will often need to refer to the
type parameters of the matched generic type. They can be easily accessed using
the dot syntax:
``sugar.extractGeneric`` or the dot syntax:

.. code-block:: nim
type Matrix[T, Rows, Columns] = object
...
proc `[]`(m: Matrix, row, col: int): Matrix.T =
m.data[col * high(Matrix.Columns) + row]
# we could've also used ``extractGeneric(Matrix, 0)``
Alternatively, the `type` operator can be used over the proc params for similar
effect when anonymous or distinct type classes are used.
Expand Down
31 changes: 31 additions & 0 deletions lib/pure/sugar.nim
Original file line number Diff line number Diff line change
Expand Up @@ -198,3 +198,34 @@ macro dump*(x: typed): untyped =
let r = quote do:
debugEcho `s`, " = ", `x`
return r

macro extractGeneric*(T: typedesc, index:static[int]): untyped =
## extract generic type numbered ``index`` used to construct ``T``. Note:
## ``-1`` returns ``Foo`` in ``Foo[T]``
runnableExamples:
type Foo[T1, T2]=object
doAssert extractGeneric(Foo[float, string], 0) is float
doAssert extractGeneric(Foo[float, string], 1) is string
doAssert extractGeneric(Foo[float, string], -1) is Foo

var impl = getTypeImpl(T)
expectKind(impl, nnkBracketExpr)
impl = impl[1]
while true:
case impl.kind
of nnkSym:
impl = impl.getImpl
continue
of nnkTypeDef:
impl = impl[2]
continue
of nnkBracketExpr:
if index == -1:
impl=impl[0] #return `Foo` in `Foo[T]`
else:
impl=impl[1+index] #return `T` in `Foo[T]` (when index = 0)
break
else:
error "internal error: impl.kind: " & $impl.kind
impl

21 changes: 21 additions & 0 deletions tests/stdlib/tsugar.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
discard """
file: "tsugar.nim"
output: ""
"""
import sugar
import macros

block extractGeneric:
type Foo[T1, T2]=object
type Foo2=Foo[float, string]
doAssert extractGeneric(Foo[float, string], 1) is string
doAssert extractGeneric(Foo2, 1) is string
# workaround for seq[int].T not working,
# see https://github.com/nim-lang/Nim/issues/8433
doAssert extractGeneric(seq[int], 0) is int
doAssert extractGeneric(seq[seq[string]], 0) is seq[string]
doAssert: not compiles(extractGeneric(seq[int], 1))
doAssert extractGeneric(seq[int], -1) is seq

type Foo3[T] = T
doAssert extractGeneric(Foo3[int], 0) is int

0 comments on commit 1c669ab

Please sign in to comment.