Consider this code:
import macros
dumpTree:
type
ObjectKind = enum
oA, oB
ObjectType = object
case kind: ObjectKind
of oA:
a: string
of oB:
b: string
ObjectType2 = object
case kind: ObjectKind
of oA: a: string
of oB: b: string
proc foo(): int = 2
proc bar(): int =
2
It outputs:
StmtList
TypeSection
TypeDef
Ident !"ObjectKind"
Empty
EnumTy
Empty
Ident !"oA"
Ident !"oB"
TypeDef
Ident !"ObjectType"
Empty
ObjectTy
Empty
Empty
RecList
RecCase
IdentDefs
Ident !"kind"
Ident !"ObjectKind"
Empty
OfBranch
Ident !"oA"
RecList
IdentDefs
Ident !"a"
Ident !"string"
Empty
OfBranch
Ident !"oB"
RecList
IdentDefs
Ident !"b"
Ident !"string"
Empty
TypeDef
Ident !"ObjectType2"
Empty
ObjectTy
Empty
Empty
RecList
RecCase
IdentDefs
Ident !"kind"
Ident !"ObjectKind"
Empty
OfBranch
Ident !"oA"
IdentDefs
Ident !"a"
Ident !"string"
Empty
OfBranch
Ident !"oB"
IdentDefs
Ident !"b"
Ident !"string"
Empty
ProcDef
Ident !"foo"
Empty
Empty
FormalParams
Ident !"int"
Empty
Empty
StmtList
IntLit 2
ProcDef
Ident !"bar"
Empty
Empty
FormalParams
Ident !"int"
Empty
Empty
StmtList
IntLit 2
As you can see, the declaration of ObjectType produces RecList s inside its case branches, while ObjectType2 does not. I think it would be good for both cases to produce the same AST since they are equivalent.
As comparison, I added the two proc defs at the end: Both produce a wrapping StmtList although one has its implementation on the same line and one in the next line.
My problem is that a specification of how the AST will look like exactly is currently missing, so I usually just look at the AST that is produced. And that way, I may overlook things like „if a variable declaration is on the same line as the of branch, no wrapping RecList is produced“.
I'd argue the StmtList for the inline body is the bug, Nim's AST was designed to be losslessly convertible into its text representation (hello, "nimfmt" tool)...
And that way, I may overlook things like „if a variable declaration is on the same line as the of branch, no wrapping RecList is produced“.
Sure, but that's just the nature of the AST, think about nnkCallKinds. And usually there are no parts in the AST that are "always" there to always ignore, so if your code unconditionally assumes a RecList, it's suspicious to begin with.
And usually there are no parts in the AST that are "always" there to always ignore
Well that's good to know :). I wrongly assumed by testing that the RecList will always be there.
I would say that there are quite some ways to describe somthing with an AST in nim. And for writing macros it can be kind of hard to deal with all those variations. For example I just assume that there is always a RecList in the OfBranch. I write my code that iterates over node that I just assumed to be a RecList, but it isn't. Then something goes wrong and I realize that my assumption that I did by testing with dumpTree was not correct, and I have to write extra code to deal with those special cases. The workflow here is not perfect, because it can be hard to predict all the variations of the AST.
This will not be a complaint though, because I honestly do not know how to make it better, it just teaches me to be careful and not use macros when it is not really suitable to do so.