1<?php
2
3declare(strict_types=1);
4
5namespace Antlr\Antlr4\Runtime\Tree;
6
7class AbstractParseTreeVisitor implements ParseTreeVisitor
8{
9    /**
10     * {@inheritdoc}
11     *
12     * The default implementation calls {@see ParseTree::accept()} on the specified tree.
13     *
14     * @return mixed
15     */
16    public function visit(ParseTree $tree)
17    {
18        return $tree->accept($this);
19    }
20
21    /**
22     * {@inheritdoc}
23     *
24     * The default implementation initializes the aggregate result to
25     * {@see AbstractParseTreeVisitor::defaultResult()}. Before visiting each
26     * child, it calls {@see AbstractParseTreeVisitor::shouldVisitNextChild()};
27     * if the result is `false` no more children are visited and the current
28     * aggregate result is returned. After visiting a child, the aggregate
29     * result is updated by calling {@see AbstractParseTreeVisitor::aggregateResult()}
30     * with the previous aggregate result and the result of visiting the child.
31     *
32     * The default implementation is not safe for use in visitors that modify
33     * the tree structure. Visitors that modify the tree should override this
34     * method to behave properly in respect to the specific algorithm in use.
35     *
36     * @return mixed
37     */
38    public function visitChildren(RuleNode $node)
39    {
40        $result = $this->defaultResult();
41
42        $n = $node->getChildCount();
43
44        for ($i=0; $i < $n; $i++) {
45            if (!$this->shouldVisitNextChild($node, $result)) {
46                break;
47            }
48
49            /** @var ParseTree $child */
50            $child = $node->getChild($i);
51
52            $childResult = $child->accept($this);
53
54            $result = $this->aggregateResult($result, $childResult);
55        }
56
57        return $result;
58    }
59
60    /**
61     * {@inheritdoc}
62     *
63     * The default implementation returns the result of
64     * {@see AbstractParseTreeVisitor::defaultResult()}.
65     *
66     * @return mixed
67     */
68    public function visitTerminal(TerminalNode $node)
69    {
70        return $this->defaultResult();
71    }
72
73    /**
74     * {@inheritdoc}
75     *
76     * The default implementation returns the result of
77     * {@see AbstractParseTreeVisitor::defaultResult()}.
78     *
79     * @return mixed
80     */
81    public function visitErrorNode(ErrorNode $tree)
82    {
83        return $this->defaultResult();
84    }
85
86    /**
87     * Gets the default value returned by visitor methods. This value is
88     * returned by the default implementations of
89     * {@see AbstractParseTreeVisitor::visitTerminal()},
90     * {@see AbstractParseTreeVisitor::visitErrorNode()}.
91     * The default implementation of {@see AbstractParseTreeVisitor::visitChildren()}
92     * initializes its aggregate result to this value.
93     *
94     * The base implementation returns `null`.
95     *
96     * @return mixed
97     */
98    protected function defaultResult()
99    {
100        return null;
101    }
102
103    /**
104     * Aggregates the results of visiting multiple children of a node. After
105     * either all children are visited or
106     * {@see AbstractParseTreeVisitor::shouldVisitNextChild()} returns `false`,
107     * the aggregate value is returned as the result of
108     * {@see AbstractParseTreeVisitor::visitChildren()}.
109     *
110     * The default implementation returns `nextResult`, meaning
111     * {@see AbstractParseTreeVisitor::visitChildren()} will return the result
112     * of the last child visited (or return the initial value if the node has
113     * no children).
114     *
115     * @param mixed $aggregate  The previous aggregate value. In the default
116     *                          implementation, the aggregate value is initialized
117     *                          to {@see AbstractParseTreeVisitor::defaultResult()},
118     *                          which is passed as the `aggregate` argument to
119     *                          this method after the first child node is visited.
120     * @param mixed $nextResult The result of the immediately preceeding call to
121     *                          visit a child node.
122     *
123     * @return mixed
124     */
125    protected function aggregateResult($aggregate, $nextResult)
126    {
127        return $nextResult;
128    }
129
130    /**
131     * This method is called after visiting each child in
132     * {@see AbstractParseTreeVisitor::visitChildren()}. This method is first
133     * called before the first child is visited; at that point `currentResult`
134     * will be the initial value (in the default implementation, the initial
135     * value is returned by a call to {@see AbstractParseTreeVisitor::defaultResult()}.
136     * This method is not called after the last child is visited.
137     *
138     * The default implementation always returns `true`, indicating that
139     * `visitChildren` should only return after all children are visited.
140     * One reason to override this method is to provide a "short circuit"
141     * evaluation option for situations where the result of visiting a single
142     * child has the potential to determine the result of the visit operation as
143     * a whole.
144     *
145     * @param RuleNode $node          The {@see RuleNode} whose children are
146     *                                currently being visited.
147     * @param mixed    $currentResult The current aggregate result of the children
148     *                                visited to the current point.
149     *
150     * @return bool `true` to continue visiting children. Otherwise return `false`
151     *              to stop visiting children and immediately return the current
152     *              aggregate result from {@see AbstractParseTreeVisitor::visitChildren()}.
153     */
154    protected function shouldVisitNextChild(RuleNode $node, $currentResult) : bool
155    {
156        return true;
157    }
158}
159