1 /* 2 * Copyright (c) 2012-2018 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 8 module antlr.v4.runtime.DiagnosticErrorListener; 9 10 import antlr.v4.runtime.BaseErrorListener; 11 import antlr.v4.runtime.InterfaceParser; 12 import antlr.v4.runtime.atn.ATNConfig; 13 import antlr.v4.runtime.atn.ATNConfigSet; 14 import antlr.v4.runtime.dfa.DFA; 15 import antlr.v4.runtime.misc.BitSet; 16 import antlr.v4.runtime.misc.Interval; 17 import std.conv; 18 import std.format; 19 20 // Class Template DiagnosticErrorListener 21 /** 22 * This implementation of {@link ANTLRErrorListener} can be used to identify 23 * certain potential correctness and performance problems in grammars. "Reports" 24 * are made by calling {@link Parser#notifyErrorListeners} with the appropriate 25 * message. 26 * 27 * <ul> 28 * <li><b>Ambiguities</b>: These are cases where more than one path through the 29 * grammar can match the input.</li> 30 * <li><b>Weak context sensitivity</b>: These are cases where full-context 31 * prediction resolved an SLL conflict to a unique alternative which equaled the 32 * minimum alternative of the SLL conflict.</li> 33 * <li><b>Strong (forced) context sensitivity</b>: These are cases where the 34 * full-context prediction resolved an SLL conflict to a unique alternative, 35 * <em>and</em> the minimum alternative of the SLL conflict was found to not be 36 * a truly viable alternative. Two-stage parsing cannot be used for inputs where 37 * this situation occurs.</li> 38 * </ul> 39 * 40 * @author Sam Harwell 41 */ 42 class DiagnosticErrorListener(U, V) : BaseErrorListener!(U, V) 43 { 44 45 /** 46 * When {@code true}, only exactly known ambiguities are reported. 47 */ 48 protected bool exactOnly; 49 50 /** 51 * Initializes a new instance of {@link DiagnosticErrorListener} which only 52 * reports exact ambiguities. 53 */ 54 public this() 55 { 56 this(true); 57 } 58 59 /** 60 * Initializes a new instance of {@link DiagnosticErrorListener}, specifying 61 * whether all ambiguities or only exact ambiguities are reported. 62 * 63 * @param exactOnly {@code true} to report only exact ambiguities, otherwise 64 * {@code false} to report all ambiguities. 65 */ 66 public this(bool exactOnly) 67 { 68 this.exactOnly = exactOnly; 69 } 70 71 /** 72 * @uml 73 * @override 74 */ 75 public override void reportAmbiguity(InterfaceParser recognizer, DFA dfa, int startIndex, int stopIndex, 76 bool exact, BitSet ambigAlts, ATNConfigSet configs) 77 { 78 if (exactOnly && !exact) { 79 return; 80 } 81 82 string format_info = "reportAmbiguity d=%s: ambigAlts=%s, input='%s'"; 83 string decision = getDecisionDescription(recognizer, dfa); 84 BitSet conflictingAlts = getConflictingAlts(ambigAlts, configs); 85 string text = recognizer.getTokenStream.getText(Interval.of(startIndex, stopIndex)); 86 string message = format(format_info, decision, conflictingAlts, text); 87 recognizer.notifyErrorListeners(message); 88 } 89 90 /** 91 * @uml 92 * @override 93 */ 94 public override void reportAttemptingFullContext(InterfaceParser recognizer, DFA dfa, int startIndex, 95 int stopIndex, BitSet conflictingAlts, ATNConfigSet configs) 96 { 97 string format_info = "reportAttemptingFullContext d=%s, input='%s'"; 98 string decision = getDecisionDescription(recognizer, dfa); 99 string text = recognizer.getTokenStream().getText(Interval.of(startIndex, stopIndex)); 100 string message = format(format_info, decision, text); 101 recognizer.notifyErrorListeners(message); 102 } 103 104 /** 105 * @uml 106 * @override 107 */ 108 public override void reportContextSensitivity(InterfaceParser recognizer, DFA dfa, int startIndex, 109 int stopIndex, int prediction, ATNConfigSet configs) 110 { 111 string format_info = "reportContextSensitivity d=%s, input='%s'"; 112 string decision = getDecisionDescription(recognizer, dfa); 113 string text = recognizer.getTokenStream().getText(Interval.of(startIndex, stopIndex)); 114 string message = format(format_info, decision, text); 115 recognizer.notifyErrorListeners(message); 116 } 117 118 protected string getDecisionDescription(InterfaceParser recognizer, DFA dfa) 119 { 120 int decision = dfa.decision; 121 int ruleIndex = dfa.atnStartState.ruleIndex; 122 123 string[] ruleNames = recognizer.getRuleNames(); 124 if (ruleIndex < 0 || ruleIndex >= ruleNames.length) { 125 return to!string(decision); 126 } 127 128 string ruleName = ruleNames[ruleIndex]; 129 if (ruleName is null || ruleName.length == 0) { 130 return to!string(decision); 131 } 132 return format("%d (%s)", decision, ruleName); 133 134 } 135 136 /** 137 * Computes the set of conflicting or ambiguous alternatives from a 138 * configuration set, if that information was not already provided by the 139 * parser. 140 * 141 * @param reportedAlts The set of conflicting or ambiguous alternatives, as 142 * reported by the parser. 143 * @param configs The conflicting or ambiguous configuration set. 144 * @return Returns {@code reportedAlts} if it is not {@code null}, otherwise 145 * returns the set of alternatives represented in {@code configs}. 146 */ 147 protected BitSet getConflictingAlts(BitSet reportedAlts, ATNConfigSet configs) 148 { 149 if (reportedAlts.length) { 150 return reportedAlts; 151 } 152 153 BitSet* result = new BitSet(); 154 foreach (ATNConfig config; configs.configs) { 155 result.set(config.alt, true); 156 } 157 158 return *result; 159 } 160 161 }