UNPKG

antlr4-runtime

Version:

JavaScript runtime for ANTLR4

104 lines (94 loc) 3.82 kB
/* 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(", ")}}`; } }