Hello everyone, so I'm trying to make a simple C compiler in Nim. I needed to
change AST node types, so I wrote something like this:
type
Ast = ref object of RootObj
A = ref object of Ast
B = ref object of Ast
B1 = ref object of B
B2 = ref object of B
C = ref object of Ast
b: B
method change(ast: var Ast) {.base.} =
discard
method change(ast: var B) =
if ast of B1:
ast = B2()
method change(ast: var C) =
ast.b.change()
Run
This worked well, so I added D:
...
type D = ref object of Ast
bs: seq[B]
...
method change(ast: var D) =
for b in ast.bs.mitems:
b.change()
Run
And this also worked well, so I decided to move this into iterator:
type
Ast = ...
iterator msub(ast: Ast): var Ast =
if ast of C:
yield ast.C.b.Ast
elif ast of D:
for b in ast.D.bs.mitems:
yield b.Ast
method change(ast: var Ast) {.base.} =
for sub in ast.msub:
sub.change()
method change(ast: var B) =
if ast of B1:
ast = B2()
Run
And suddenly this didn't work. Also it raised error not in the Nim compiler but
in the gcc. Here is the error for the sake of completeness:
error: '*b' is a pointer; did you mean to use '->'?
sub = &b->Sup;
^~
->
Run
I read some related issues, and found out that accroding to Araq `var Ast` and
`var B` have no subtype relation, so all of this was invalid.
While I don't understand why that should be that way, I also don't understand
how things like that should be written in Nim. Or should I return changed
version of AST node? This is still strange to me. Also, why the compiler
allowed me to use that before, but didn't allow it when I switched to
iterators? Could someone please explain that to me?