See https://llvm.org/docs/HowToSetUpLLVMStyleRTTI.html
The upshot is keeping an enum of all possible node types and then storing that value on each instantiated object. The benefit is much faster type checking and casting, the downside is a small increase in the memory footprint of each instantiated object. Also a decent amount of boilerplate.