antlr4-runtime
Version:
JavaScript runtime for ANTLR4
104 lines (94 loc) • 3.82 kB
JavaScript
/* Copyright (c) 2012-2022 The ANTLR Project. All rights reserved.
* Use of this file is governed by the BSD 3-clause license that
* can be found in the LICENSE.txt file in the project root.
*/
import ErrorListener from './ErrorListener.js';
import Interval from '../misc/Interval.js';
import BitSet from "../misc/BitSet.js";
/**
* This implementation of {@link ANTLRErrorListener} can be used to identify
* certain potential correctness and performance problems in grammars. "Reports"
* are made by calling {@link Parser//notifyErrorListeners} with the appropriate
* message.
*
* <ul>
* <li><b>Ambiguities</b>: These are cases where more than one path through the
* grammar can match the input.</li>
* <li><b>Weak context sensitivity</b>: These are cases where full-context
* prediction resolved an SLL conflict to a unique alternative which equaled the
* minimum alternative of the SLL conflict.</li>
* <li><b>Strong (forced) context sensitivity</b>: These are cases where the
* full-context prediction resolved an SLL conflict to a unique alternative,
* <em>and</em> the minimum alternative of the SLL conflict was found to not be
* a truly viable alternative. Two-stage parsing cannot be used for inputs where
* this situation occurs.</li>
* </ul>
*/
export default class DiagnosticErrorListener extends ErrorListener {
constructor(exactOnly) {
super();
exactOnly = exactOnly || true;
// whether all ambiguities or only exact ambiguities are reported.
this.exactOnly = exactOnly;
}
reportAmbiguity(recognizer, dfa, startIndex, stopIndex, exact, ambigAlts, configs) {
if (this.exactOnly && !exact) {
return;
}
const msg = "reportAmbiguity d=" +
this.getDecisionDescription(recognizer, dfa) +
": ambigAlts=" +
this.getConflictingAlts(ambigAlts, configs) +
", input='" +
recognizer.getTokenStream().getText(new Interval(startIndex, stopIndex)) + "'"
recognizer.notifyErrorListeners(msg);
}
reportAttemptingFullContext(recognizer, dfa, startIndex, stopIndex, conflictingAlts, configs) {
const msg = "reportAttemptingFullContext d=" +
this.getDecisionDescription(recognizer, dfa) +
", input='" +
recognizer.getTokenStream().getText(new Interval(startIndex, stopIndex)) + "'"
recognizer.notifyErrorListeners(msg);
}
reportContextSensitivity(recognizer, dfa, startIndex, stopIndex, prediction, configs) {
const msg = "reportContextSensitivity d=" +
this.getDecisionDescription(recognizer, dfa) +
", input='" +
recognizer.getTokenStream().getText(new Interval(startIndex, stopIndex)) + "'"
recognizer.notifyErrorListeners(msg);
}
getDecisionDescription(recognizer, dfa) {
const decision = dfa.decision
const ruleIndex = dfa.atnStartState.ruleIndex
const ruleNames = recognizer.ruleNames
if (ruleIndex < 0 || ruleIndex >= ruleNames.length) {
return "" + decision;
}
const ruleName = ruleNames[ruleIndex] || null
if (ruleName === null || ruleName.length === 0) {
return "" + decision;
}
return `${decision} (${ruleName})`;
}
/**
* Computes the set of conflicting or ambiguous alternatives from a
* configuration set, if that information was not already provided by the
* parser.
*
* @param reportedAlts The set of conflicting or ambiguous alternatives, as
* reported by the parser.
* @param configs The conflicting or ambiguous configuration set.
* @return Returns {@code reportedAlts} if it is not {@code null}, otherwise
* returns the set of alternatives represented in {@code configs}.
*/
getConflictingAlts(reportedAlts, configs) {
if (reportedAlts !== null) {
return reportedAlts;
}
const result = new BitSet()
for (let i = 0; i < configs.items.length; i++) {
result.add(configs.items[i].alt);
}
return `{${result.values().join(", ")}}`;
}
}