Sometimes I have loops like
for state in 0 .. 1:
....
if state == 0:
....
It would be better iterating over enums, like
type
Color = enum
red, green, blue
for c in Color:
echo c
if c == red:
echo "caution"
But I am too lazy to define the enum type ONLY for this, so I wonder if something like
for c in enum(red, green, blue):
echo c
if c == red:
echo "caution"
may be possible?
c in Color.low..Color.high: echo c
You can use a {.experimental: "ForLoopMacros".} to rewrite the for loop.
See for example the impelmentation of Python enumerate
import macros
{.experimental: "forLoopMacros".}
macro enumerate*(x: ForLoopStmt): untyped =
expectKind x, nnkForStmt
# we strip off the first for loop variable and use
# it as an integer counter:
result = newStmtList()
result.add newVarStmt(x[0], newLit(0))
var body = x[^1]
if body.kind != nnkStmtList:
body = newTree(nnkStmtList, body)
body.add newCall(bindSym"inc", x[0])
var newFor = newTree(nnkForStmt)
for i in 1..x.len-3:
newFor.add x[i]
# transform enumerate(X) to 'X'
newFor.add x[^2][1]
newFor.add body
result.add newFor
and usage
for a, b in enumerate(items([1, 2, 3])):
echo a, " ", b
I'll have a look at refactoring that for enums (unless someone gives it a go first) though I fear it might only work at top level.
Also I'm pretty sure you meant narimiran instead of me ;).
for c in Color.low..Color.high produces enums, its what the for c in Color iterator does.
Anyway, its pretty easy. The enum values are scoped. With some more state keeping and macro sugar you can even define and use anon enums as function params.
import
macros
macro Enum*(fields: varargs[untyped]): untyped =
var name = "Enum"
result = nnkEnumTy.newTree(newNimNode(nnkEmpty))
for f in fields:
name &= f.strVal
result.add(f)
result =
nnkStmtList.newTree(
nnkTypeSection.newTree(
nnkTypeDef.newTree(
ident(name),
newNimNode(nnkEmpty),
result)),
ident(name))
for c in Enum(Red, Green, Blue):
if c == Green:
echo "green"
else:
echo "not green"
# echo Green # Error: undeclared identifier
slightly modified from here: https://github.com/dumjyl/stdext/blob/master/src/stdext/anon.nimbut it failed for this kind of non-sequential enum
type
Index = enum
idx1
idx2 = 5
idx3
for i in Index.low .. Index.high:
echo i
This works for holy enums:
import std/setutils
for i in Index.fullSet:
echo i
import std/enumutils
# std/enumutils implements the items iterator for holey enums.
# I believe system defines items for ordinal types, which includes sinner enums
type
OEnum {.pure.} = enum
Zero,
One,
Two,
Three
HEnum {.pure.} = enum
Zero,
One,
Five = 5,
Six
proc echoEnum(e: typedesc[enum]) =
for v in e:
echo v, " -> ", v.ord
echoEnum OEnum
echo "" # Add a newline for space
echoEnum HEnum
Ironically, playground is 502, so here's RainbowAsteroids' paste directly from ix.io:
import std/enumutils
# std/enumutils implements the items iterator for holey enums.
# I believe system defines items for ordinal types, which includes sinner enums
type
OEnum {.pure.} = enum
Zero,
One,
Two,
Three
HEnum {.pure.} = enum
Zero,
One,
Five = 5,
Six
proc echoEnum(e: typedesc[enum]) =
for v in e:
echo v, " -> ", v.ord
echoEnum OEnum
echo "" # Add a newline for space
echoEnum HEnum