package com.abusalimov.mrcalc.ast;

import com.abusalimov.mrcalc.ast.expr.*;
import com.abusalimov.mrcalc.ast.stmt.ExprStmtNode;
import com.abusalimov.mrcalc.ast.stmt.StmtNode;
import com.abusalimov.mrcalc.ast.stmt.VarDefStmtNode;

/**
 * Basic AST visitor using a double-dispatch pattern. Subclasses of {@link Node} should overload the
 * {@link Node#accept(NodeVisitor)} method to the appropriate {@link #doVisit(Node)} method of the
 * visitor.
 *
 * @param <T> The return type of the {@link #visit(Node)} (and hence the {@link #doVisit(Node)})
 *            operation.
 */
public interface NodeVisitor<T> {

    /**
     * Visit a node, and return a user-defined result of the operation.
     *
     * @param node The subtree to visit.
     * @return The result of visiting the node.
     */
    default T visit(Node node) {
        return node.accept(this);  // double dispatch
    }

    /**
     * Visit the children of a node, and return a user-defined result of the operation.
     *
     * @param node The subtree whose children should be visited.
     */
    default void visitChildren(Node node) {
        node.getChildren().forEach(this::visit);
    }

    default T defaultVisit(Node node) {
        visitChildren(node);
        return null;
    }

    default T doVisit(Node node) {
        return defaultVisit(node);
    }

    default T doVisit(ProgramNode node) {
        return doVisit((Node) node);
    }

    default T doVisit(StmtNode node) {
        return doVisit((Node) node);
    }

    default T doVisit(ExprStmtNode node) {
        return doVisit((StmtNode) node);
    }

    default T doVisit(VarDefStmtNode node) {
        return doVisit((StmtNode) node);
    }

    default T doVisit(ExprNode node) {
        return doVisit((Node) node);
    }

    default T doVisit(VarRefNode node) {
        return doVisit((ExprNode) node);
    }

    default T doVisit(LiteralNode node) {
        return doVisit((ExprNode) node);
    }

    default T doVisit(BinaryOpNode node) {
        return doVisit((ExprNode) node);
    }

    default T doVisit(UnaryOpNode node) {
        return doVisit((ExprNode) node);
    }
}

@@ -225,16 +225,76 @@
 tNode;%0A%0A
+import java.util.List;%0Aimport java.util.stream.Collectors;%0A%0A
 /**%0A * B
@@ -990,61 +990,10 @@
 node
-, and return a user-defined result of the operation
 .%0A
+
     
@@ -1104,32 +1104,32 @@
 en(Node node) %7B%0A
-
         node.get
@@ -1160,32 +1160,406 @@
 :visit);%0A    %7D%0A%0A
+    /**%0A     * Visit the children of a node, and return a user-defined result of the operation.%0A     *%0A     * @param node The subtree whose children should be visited.%0A     */%0A    default List%3C? extends T%3E visitChildrenWithResult(Node node) %7B%0A        return node.getChildren().stream()%0A                .map(this::visit)%0A                .collect(Collectors.toList());%0A    %7D%0A%0A
     default T de

Add NodeVisitor.visitChildrenWithResult() helper