1   /*
2    * SPDX-FileCopyrightText: none
3    * SPDX-License-Identifier: CC0-1.0
4    */
5   
6   package gov.nist.secauto.metaschema.core.metapath.antlr;
7   
8   import org.antlr.v4.runtime.ParserRuleContext;
9   import org.antlr.v4.runtime.RuleContext;
10  import org.antlr.v4.runtime.tree.ParseTree;
11  
12  import java.io.PrintStream;
13  
14  public class ParseTreePrinter {
15    private final PrintStream outputStream;
16    private boolean ignoringWrappers = true;
17  
18    /**
19     * Construct a new concrete syntax tree (CST) printer.
20     *
21     * @param outputStream
22     *          the stream to print to
23     */
24    public ParseTreePrinter(PrintStream outputStream) {
25      this.outputStream = outputStream;
26    }
27  
28    /**
29     * Set the behavior for handling wrapper nodes in the CST hierarchy.
30     *
31     * @param ignoringWrappers
32     *          {@code true} if wrappers should be ignored or {@code false}
33     *          otherwise
34     */
35    public void setIgnoringWrappers(boolean ignoringWrappers) {
36      this.ignoringWrappers = ignoringWrappers;
37    }
38  
39    /**
40     * Print a given CST {@link ParseTree} using the provided {@code ruleNames}.
41     *
42     * @param tree
43     *          the CST parse tree
44     * @param ruleNames
45     *          the list of rule names to use for human readability
46     */
47    @SuppressWarnings("PMD.UseVarargs")
48    public void print(ParseTree tree, String[] ruleNames) {
49      explore((RuleContext) tree.getPayload(), 0, ruleNames);
50    }
51  
52    @SuppressWarnings("PMD.UseVarargs")
53    private void explore(RuleContext ctx, int indentation, String[] ruleNames) {
54      boolean toBeIgnored = ignoringWrappers && ctx.getChildCount() == 1 && ctx.getChild(0) instanceof ParserRuleContext;
55      String ruleName = ruleNames[ctx.getRuleIndex()];
56      for (int i = 0; i < indentation; i++) {
57        outputStream.print("  ");
58      }
59      outputStream.print(ruleName);
60      if (toBeIgnored) {
61        outputStream.print("(ignored)");
62      }
63      outputStream.print(": ");
64      outputStream.print(ctx.getText());
65      outputStream.println();
66  
67      for (int i = 0; i < ctx.getChildCount(); i++) {
68        ParseTree element = ctx.getChild(i);
69        if (element instanceof RuleContext) {
70          explore((RuleContext) element, indentation + 1, ruleNames);
71        }
72      }
73    }
74  }