4 ms·
One question I always ask myself when I see a crate that uses macros is "how much will this crate disrupt my IDE experience?" If it breaks rename and goto defin
by hardwaregeek 3y ago
One question I always ask myself when I see a crate that uses macros is "how much will this crate disrupt my IDE experience?" If it breaks rename and goto definition, then I'm not sure it's worth it. Especially with AST definitions where I will be going back to my AST definition a lot.
Also, I find the whole visitor pattern abstraction a little pointless in Rust.
I can't help but feel that applying a visitor pattern is taking an idiosyncrasy of object oriented programming and forcing it into Rust. Basically abstraction for abstraction's sake. I'd much rather write a bunch of `visit_expr`, `visit_stmt` (really `type_check_expr`, `type_check_stmt`) functions that pattern match on the data. It's much more searchable, and condenses the information at the pass level and not the data structure level. I care much more about having all of my type checking methods in one place, than I care about having all of the transformations of `Expr` in one place. I suppose if you're doing a lot of passes over the same representation and you need to schedule them in an efficient way, a visitor pattern could work. But how often are you doing that? Maybe if you're writing an optimizer but more often than not I'm doing a transformation pass from one IR to another.
With that said I can sympathize with ASTs being a lot of boilerplate. It took a lot of typing to thread location data through my AST.
- linkdd 3y agoThe rust-analyzer extension for VSCode is quite good for this. Though, I should try to use `quote_spanned!` instead of `quote!`, but I'm kind of a newbie with proc-macros. As for your take on the visitor pattern. In my previous code, I had the `visit_expr`, `visit_stmt`, etc... And it's a lot of boilerplate, I wanted to reduce the amount of copy/paste and facilitate refactoring, hence my DSL. I do have multiple phases during compilation where I walk the AST and the "only" difference is the return value of those `visit_*` functions and their body. Here, I just have to use a `model!{}` macro for each "phase", which is less boilerplate code. In the end, it's just static dispatch through the use of a trait that I called "Visitable".