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