add typetraits.OrdinalEnum, enumutils.symbolName (#17281)

This commit is contained in:
Timothee Cour 2021-03-10 08:08:24 -08:00 • committed by GitHub
commit eb07a5a75b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 57 additions and 9 deletions

View file

@ -47,8 +47,9 @@
- Added `std/enumutils` module. Added `genEnumCaseStmt` macro that generates case statement to parse string to enum. - Added `std/enumutils` module. Added `genEnumCaseStmt` macro that generates case statement to parse string to enum.
Added `items` for enums with holes. Added `items` for enums with holes.
Added `symbolName` to return the enum symbol name ignoring the human readable name.
- Added `typetraits.SomeEnumWithHoles` for enums with holes. - Added `typetraits.HoleyEnum` for enums with holes, `OrdinalEnum` for enums without holes.
- Removed deprecated `iup` module from stdlib, it has already moved to - Removed deprecated `iup` module from stdlib, it has already moved to
[nimble](https://github.com/nim-lang/iup). [nimble](https://github.com/nim-lang/iup).

View file

@ -15,16 +15,20 @@
import std/private/since import std/private/since
export system.`$` # for backward compatibility export system.`$` # for backward compatibility
type SomeEnumWithHoles* = (not Ordinal) and enum ## Enum with holes. type HoleyEnum* = (not Ordinal) and enum ## Enum with holes.
type OrdinalEnum* = Ordinal and enum ## Enum without holes.
runnableExamples: runnableExamples:
type A = enum a0 = 2, a1 = 4, a2 type A = enum a0 = 2, a1 = 4, a2
type B = enum b0 = 2, b1, b2 type B = enum b0 = 2, b1, b2
assert A is SomeEnumWithHoles assert A is enum
assert B isnot SomeEnumWithHoles assert A is HoleyEnum
assert int isnot SomeEnumWithHoles assert A isnot OrdinalEnum
assert B isnot HoleyEnum
assert B is OrdinalEnum
assert int isnot HoleyEnum
type C[T] = enum h0 = 2, h1 = 4 type C[T] = enum h0 = 2, h1 = 4
assert C[float] is SomeEnumWithHoles assert C[float] is HoleyEnum
proc name*(t: typedesc): string {.magic: "TypeTrait".} = proc name*(t: typedesc): string {.magic: "TypeTrait".} =
## Returns the name of the given type. ## Returns the name of the given type.

View file

@ -8,6 +8,7 @@
# #
import std/macros import std/macros
from std/typetraits import OrdinalEnum, HoleyEnum
# xxx `genEnumCaseStmt` needs tests and runnableExamples # xxx `genEnumCaseStmt` needs tests and runnableExamples
@ -65,10 +66,17 @@ macro genEnumCaseStmt*(typ: typedesc, argSym: typed, default: typed,
expectKind(default, nnkSym) expectKind(default, nnkSym)
result.add nnkElse.newTree(default) result.add nnkElse.newTree(default)
macro enumWithHolesFullRange(a: typed): untyped = macro enumFullRange(a: typed): untyped =
newNimNode(nnkCurly).add(a.getType[1][1..^1]) newNimNode(nnkCurly).add(a.getType[1][1..^1])
iterator items*[T: enum and not Ordinal](E: typedesc[T]): T = macro enumNames(a: typed): untyped =
# this could be exported too; in particular this could be useful for enum with holes.
result = newNimNode(nnkBracket)
for ai in a.getType[1][1..^1]:
assert ai.kind == nnkSym
result.add newLit ai.strVal
iterator items*[T: HoleyEnum](E: typedesc[T]): T =
## Iterates over an enum with holes. ## Iterates over an enum with holes.
runnableExamples: runnableExamples:
type A = enum a0 = 2, a1 = 4, a2 type A = enum a0 = 2, a1 = 4, a2
@ -76,4 +84,18 @@ iterator items*[T: enum and not Ordinal](E: typedesc[T]): T =
from std/sequtils import toSeq from std/sequtils import toSeq
assert A.toSeq == [a0, a1, a2] assert A.toSeq == [a0, a1, a2]
assert B[float].toSeq == [B[float].b0, B[float].b1] assert B[float].toSeq == [B[float].b0, B[float].b1]
for a in enumWithHolesFullRange(E): yield a for a in enumFullRange(E): yield a
func symbolName*[T: OrdinalEnum](a: T): string =
## Returns the symbol name of an enum.
runnableExamples:
type B = enum
b0 = (10, "kb0")
b1 = "kb1"
b2
let b = B.low
assert b.symbolName == "b0"
assert $b == "kb0"
static: assert B.high.symbolName == "b2"
const names = enumNames(T)
names[a.ord - T.low.ord]

View file

@ -12,5 +12,26 @@ template main =
doAssert A.toSeq == [a0, a1, a2] doAssert A.toSeq == [a0, a1, a2]
doAssert B[float].toSeq == [B[float].b0, B[float].b1] doAssert B[float].toSeq == [B[float].b0, B[float].b1]
block: # symbolName
block:
type A2 = enum a20, a21, a22
doAssert $a21 == "a21"
doAssert a21.symbolName == "a21"
proc `$`(a: A2): string = "foo"
doAssert $a21 == "foo"
doAssert a21.symbolName == "a21"
var a = a22
doAssert $a == "foo"
doAssert a.symbolName == "a22"
type B = enum
b0 = (10, "kb0")
b1 = "kb1"
b2
let b = B.low
doAssert b.symbolName == "b0"
doAssert $b == "kb0"
static: doAssert B.high.symbolName == "b2"
static: main() static: main()
main() main()