> I do remember him using the visitor pattern to implement part of the parser I think. I thought that was kind of an odd choice, especially since it seemed like he was really just trying to avoid Java boilerplate.

It's used to allow writing a "resolver" and an "interpreter" that both know how to handle every type of node in the AST. It's almost a functional approach, and I actually think it might increase boilerplate because Java is more designed around the object-oriented approach of adding `resolve` and `interpret` methods directly to each node type.

The two approaches result in very different code organisation, though - maybe the visitor approach was easier to explain in prose.

It's been a while since I read it, but I remember him saying something about the more natural (my word not his) approach being a single data structure that you would pass through both components, but he didn't want to do that because Java doesnt really encourage that kind of design, and you have a bunch of boilerplate for each class. It just struck me as an odd choice since the book was more about compiler/interpreter fundamentals, and I feel like the visitor pattern is a bit in the weeds in terms of OOP design.

I wonder if he wrote today if he would have used a Record and done the more straightforward implementation.

I went through the Crafting Interpreters book with modern Java. I posted this on reddit, but I basically used records and sealed interfaces. With modern Java there's no need for visitor pattern.

    private void execute(Stmt statement) {
        switch (statement) {
            case Stmt.Expression expression -> evaluate(expression.expr());
            case Stmt.Block block -> executeBlock(block.statements(),
               new Environment(environment));
            ...

    public sealed interface Expr permits
        Expr.Assign,
        Expr.Binary,
        Expr.Call,
        Expr.Function,
        .... more exprs here

Interesting. Almost all my actual experience writing Java is in Java 8, so I'm not super familiar with the modern stuff (other then a few things like Records). I'll have to take a look.

Most of the people I know who write Java would have an aneurysm at seeing a switch statement.

To be clear, that's a critique of the Java mindset, not your code. Lol