I have a variant object with 7 different kinds that I want to do some operations on (eg. addition, multiplication) but it becomes really ugly as I have to nest two case statements and end up with 49 branches in the end and that's really ugly. Here's what it looks like currently when I only populate one of the nested case statements:
case a.kind
of symNumber:
case b.kind
of symNumber:
discard
of symSymbol:
discard
of symFunc:
discard
of symMul:
discard
of symAdd:
discard
of symPow:
discard
of symSpecial:
discard
of symSymbol:
discard
of symFunc:
discard
of symMul:
discard
of symAdd:
discard
of symPow:
discard
of symSpecial:
discard
Most of the operations is independent on which order the parameters are passed in so those would only require one of the branches but some of them requires both. In the future if I want to add a new kind I have the advantage of knowing exactly where I have to add it but there are so many places that I'd have to change. It feels like there should be a "magic macro"-way to handle this more efficiently or more compactly at least. Have anyone else had this inconviniece before and even found a good solution to it? :D
type
Kind1 = enum
k1First
k1Second
k1Third
Kidn2 = enum
k2First
k2Second
k2Third
case (k1First, k2Second):
of (in {k1First, k1Second}, _):
echo "123"
oh I had a similar problem when decoding powerpc instructions. What I ended up with was a macro which among other things "unrolled" the branches using a table. This would look kind off like this for your example:
const offsets: array[Sym, int] = [ord(high(Sym))+1, 0, 0, #[ecetera]#]
case ord(a.kind) + offsets[a.kind]
# all the cases which can be decoded based on the first part
of 0: discard
of 1: discard
# …
of ord(high(Sym))+1: # when a.kind == symNumber and b.kind == symNumber:
discard
of ord(high(Sym))+2: # when a.kind == symNumber and b.kind == symSymbol:
discard
Another advantage this brought me was that I could use computed goto for the interpreter.