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  import org.eclipse.jdt.annotation.NotOwning;
12  
13  import java.io.PrintStream;
14  
15  import edu.umd.cs.findbugs.annotations.NonNull;
16  
17  /**
18   * Supports walking an ANTLR parse tree to generate a textual representation of
19   * the tree.
20   */
21  public class ParseTreePrinter {
22    @SuppressWarnings("resource")
23    @NotOwning
24    @NonNull
25    private final PrintStream outputStream;
26    private boolean ignoringWrappers = true;
27  
28    /**
29     * Construct a new concrete syntax tree (CST) printer.
30     *
31     * @param outputStream
32     *          the stream to print to
33     */
34    public ParseTreePrinter(@NotOwning @NonNull PrintStream outputStream) {
35      this.outputStream = outputStream;
36    }
37  
38    /**
39     * Set the behavior for handling wrapper nodes in the CST hierarchy.
40     *
41     * @param ignoringWrappers
42     *          {@code true} if wrappers should be ignored or {@code false}
43     *          otherwise
44     */
45    public void setIgnoringWrappers(boolean ignoringWrappers) {
46      this.ignoringWrappers = ignoringWrappers;
47    }
48  
49    /**
50     * Print a given CST {@link ParseTree} using the provided {@code ruleNames}.
51     *
52     * @param tree
53     *          the CST parse tree
54     * @param ruleNames
55     *          the list of rule names to use for human readability
56     */
57    @SuppressWarnings("PMD.UseVarargs")
58    public void print(ParseTree tree, String[] ruleNames) {
59      explore((RuleContext) tree.getPayload(), 0, ruleNames);
60    }
61  
62    @SuppressWarnings("PMD.UseVarargs")
63    private void explore(RuleContext ctx, int indentation, String[] ruleNames) {
64      boolean toBeIgnored = ignoringWrappers && ctx.getChildCount() == 1 && ctx.getChild(0) instanceof ParserRuleContext;
65      String ruleName = ruleNames[ctx.getRuleIndex()];
66      for (int i = 0; i < indentation; i++) {
67        outputStream.print("  ");
68      }
69      outputStream.print(ruleName);
70      if (toBeIgnored) {
71        outputStream.print("(ignored)");
72      }
73      outputStream.print(": ");
74      outputStream.print(ctx.getText());
75      outputStream.println();
76  
77      for (int i = 0; i < ctx.getChildCount(); i++) {
78        ParseTree element = ctx.getChild(i);
79        if (element instanceof RuleContext) {
80          explore((RuleContext) element, indentation + 1, ruleNames);
81        }
82      }
83    }
84  }