My suggestion is Crafting Interpreters + a different programming language to Java.
YMMV, but it's hard to genuinely learn from Crafting Interpreters. All the code is already written for you.
YMMV, but it's hard to genuinely learn from Crafting Interpreters. All the code is already written for you.
Another strategy I used was to look at the title of the chapter, then work ahead as much as possible to implement that. It really helped my learning process to naturally explore the problem space myself, then read through and see how my naive attempts compared to a more seasoned implementation. But as the parent said, ymmv!
I got rid of the code gen and visitor pattern stuff by using records in C# with pattern matching which felt a lot simpler to me.