Skip to content

Commit

Permalink
test: pass appropriate error handler for antlr adapter
Browse files Browse the repository at this point in the history
Signed-off-by: Aman Prashant <aman.prashant@broadcom.com>
  • Loading branch information
ap891843 authored and ishche committed May 30, 2024
1 parent 89d963a commit ad09782
Show file tree
Hide file tree
Showing 11 changed files with 161 additions and 141 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
/*
* Copyright (c) 2024 Broadcom.
* The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries.
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Broadcom, Inc. - initial API and implementation
*
*/
package org.eclipse.lsp.cobol.core.strategy;

import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.antlr.v4.runtime.*;
import org.eclipse.lsp.cobol.common.message.MessageService;
import org.eclipse.lsp.cobol.common.message.MessageServiceProvider;

/**
* This implementation of the error strategy customizes error messages that are extracted from the
* parsing exceptions
*/
@Slf4j
// for test
@NoArgsConstructor
public class BasicCobolErrorHandler extends DefaultErrorStrategy implements MessageServiceProvider {
private static final String REPORT_NO_VIABLE_ALTERNATIVE =
"ErrorStrategy.reportNoViableAlternative";
private static final String REPORT_MISSING_TOKEN = "ErrorStrategy.reportMissingToken";

@Getter
@Setter
private MessageService messageService;
@Getter @Setter private ErrorMessageHelper errorMessageHelper;

public BasicCobolErrorHandler(MessageService messageService) {
this.messageService = messageService;
this.errorMessageHelper = new ErrorMessageHelper(messageService);
}

@Override
public void reportError(Parser recognizer, RecognitionException e) {
// if we've already reported an error and have not matched a token
// yet successfully, don't report any errors.
if (!inErrorRecoveryMode(recognizer)) {
beginErrorCondition(recognizer);
reportErrorByType(recognizer, e);
}
}

private void reportErrorByType(Parser recognizer, RecognitionException e) {
if (e instanceof InputMismatchException) {
reportInputMismatch(recognizer, (InputMismatchException) e);
return;
}
if (e instanceof NoViableAltException) {
reportNoViableAlternative(recognizer, (NoViableAltException) e);
return;
}
if (e instanceof FailedPredicateException) {
reportFailedPredicate(recognizer, (FailedPredicateException) e);
return;
}
reportUnrecognizedException(recognizer, e);
}

private void reportUnrecognizedException(Parser recognizer, RecognitionException e) {
LOG.error("unknown recognition error type: " + e.getClass().getName());
recognizer.notifyErrorListeners(e.getOffendingToken(), e.getMessage(), e);
}

@Override
protected void reportInputMismatch(Parser recognizer, InputMismatchException e) {
Token token = e.getOffendingToken();
String msg =
errorMessageHelper.getInputMismatchMessage(recognizer, e, token, getOffendingToken(e));
recognizer.notifyErrorListeners(token, msg, e);
}

@Override
protected void reportNoViableAlternative(Parser recognizer, NoViableAltException e) {
String messageParams = errorMessageHelper.retrieveInputForNoViableException(recognizer, e);
String msg = messageService.getMessage(REPORT_NO_VIABLE_ALTERNATIVE, messageParams);
recognizer.notifyErrorListeners(e.getOffendingToken(), msg, e);
}

@Override
protected void reportUnwantedToken(Parser recognizer) {
if (inErrorRecoveryMode(recognizer)) {
return;
}
beginErrorCondition(recognizer);
Token currentToken = recognizer.getCurrentToken();
String msg =
errorMessageHelper.getUnwantedTokenMessage(
recognizer, currentToken, getTokenErrorDisplay(currentToken));
recognizer.notifyErrorListeners(currentToken, msg, null);
}

@Override
protected void reportMissingToken(Parser recognizer) {
if (inErrorRecoveryMode(recognizer)) {
return;
}
beginErrorCondition(recognizer);
String msg =
messageService.getMessage(
REPORT_MISSING_TOKEN,
errorMessageHelper.getExpectedText(recognizer),
ErrorMessageHelper.getRule(recognizer));
recognizer.notifyErrorListeners(getPreviousToken(recognizer), msg, null);
}

private Token getPreviousToken(Parser recognizer) {
if (recognizer.getCurrentToken().getText().trim().length() == 1) {
return recognizer.getCurrentToken();
}
int index = recognizer.getCurrentToken().getTokenIndex();
while (index > 0) {
index--;
Token token = recognizer.getTokenStream().get(index);
if (!token.getText().trim().isEmpty()) {
return token;
}
}
return recognizer.getCurrentToken();
}

private String getOffendingToken(InputMismatchException e) {
return getTokenErrorDisplay(e.getOffendingToken());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,56 +17,36 @@
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.antlr.v4.runtime.*;
import org.antlr.v4.runtime.atn.ATNState;
import org.antlr.v4.runtime.misc.IntervalSet;
import org.eclipse.lsp.cobol.common.message.MessageService;
import org.eclipse.lsp.cobol.common.message.MessageServiceProvider;
import org.eclipse.lsp.cobol.core.CobolLexer;
import org.eclipse.lsp.cobol.core.CobolParser;
import org.eclipse.lsp.cobol.core.MessageServiceParser;

/**
* This implementation of the error strategy customizes error messages that are extracted from the
* parsing exceptions
* parsing exceptions and changes the sync strategy adopted specific to the COBOL language
*/
@Slf4j
// for test
@NoArgsConstructor
public class CobolErrorStrategy extends DefaultErrorStrategy implements MessageServiceProvider {
private static final String REPORT_NO_VIABLE_ALTERNATIVE =
"ErrorStrategy.reportNoViableAlternative";
private static final String REPORT_MISSING_TOKEN = "ErrorStrategy.reportMissingToken";

@Getter @Setter private MessageService messageService;
@Getter @Setter private ErrorMessageHelper errorMessageHelper;
public class CobolErrorStrategy extends BasicCobolErrorHandler {

public CobolErrorStrategy(MessageService messageService) {
this.messageService = messageService;
this.errorMessageHelper = new ErrorMessageHelper(messageService);
}

@Override
public void reportError(Parser recognizer, RecognitionException e) {
// if we've already reported an error and have not matched a token
// yet successfully, don't report any errors.
if (!inErrorRecoveryMode(recognizer)) {
beginErrorCondition(recognizer);
reportErrorByType(recognizer, e);
}
super(messageService);
}

/**
*
* This is a Cobol specific method adopted from {@link DefaultErrorStrategy#sync(Parser)}
*
* The Cobol specific implementation of {@link ANTLRErrorStrategy#sync} makes sure that the current
* lookahead symbol is consistent with what were expecting at this point in the ATN. You can call
* this anytime but ANTLR only generates code to check before subrules/loops and each iteration.
* <p>The Cobol specific implementation of {@link ANTLRErrorStrategy#sync} makes sure that the
* current lookahead symbol is consistent with what were expecting at this point in the ATN. You
* can call this anytime but ANTLR only generates code to check before subrules/loops and each
* iteration.
*
* <p>Implements Jim Idle's magic sync mechanism in closures and optional subrules. E.g.,
*
Expand Down Expand Up @@ -193,86 +173,7 @@ private static boolean shouldSkipToSync(
return (nextTokens.contains(CobolLexer.DOT_FS) || nextTokens.contains(CobolLexer.DOT_FS2))
&& !nextTokens.contains(Token.EOF)
&& la != Token.EOF
&& (lastToken.isPresent()
&& !getSkipToTokenList().contains(lastToken.get()));
}

private void reportErrorByType(Parser recognizer, RecognitionException e) {
if (e instanceof InputMismatchException) {
reportInputMismatch(recognizer, (InputMismatchException) e);
return;
}
if (e instanceof NoViableAltException) {
reportNoViableAlternative(recognizer, (NoViableAltException) e);
return;
}
if (e instanceof FailedPredicateException) {
reportFailedPredicate(recognizer, (FailedPredicateException) e);
return;
}
reportUnrecognizedException(recognizer, e);
}

private void reportUnrecognizedException(Parser recognizer, RecognitionException e) {
LOG.error("unknown recognition error type: " + e.getClass().getName());
recognizer.notifyErrorListeners(e.getOffendingToken(), e.getMessage(), e);
}

@Override
protected void reportInputMismatch(Parser recognizer, InputMismatchException e) {
Token token = e.getOffendingToken();
String msg =
errorMessageHelper.getInputMismatchMessage(recognizer, e, token, getOffendingToken(e));
recognizer.notifyErrorListeners(token, msg, e);
}

@Override
protected void reportNoViableAlternative(Parser recognizer, NoViableAltException e) {
String messageParams = errorMessageHelper.retrieveInputForNoViableException(recognizer, e);
String msg = messageService.getMessage(REPORT_NO_VIABLE_ALTERNATIVE, messageParams);
recognizer.notifyErrorListeners(e.getOffendingToken(), msg, e);
}

@Override
protected void reportUnwantedToken(Parser recognizer) {
if (inErrorRecoveryMode(recognizer)) {
return;
}
beginErrorCondition(recognizer);
Token currentToken = recognizer.getCurrentToken();
String msg =
errorMessageHelper.getUnwantedTokenMessage(
recognizer, currentToken, getTokenErrorDisplay(currentToken));
recognizer.notifyErrorListeners(currentToken, msg, null);
}

@Override
protected void reportMissingToken(Parser recognizer) {
if (inErrorRecoveryMode(recognizer)) {
return;
}
beginErrorCondition(recognizer);
String msg =
messageService.getMessage(
REPORT_MISSING_TOKEN,
errorMessageHelper.getExpectedText(recognizer),
ErrorMessageHelper.getRule(recognizer));
recognizer.notifyErrorListeners(getPreviousToken(recognizer), msg, null);
}

private Token getPreviousToken(Parser recognizer) {
if (recognizer.getCurrentToken().getText().trim().length() == 1) {
return recognizer.getCurrentToken();
}
int index = recognizer.getCurrentToken().getTokenIndex();
while (index > 0) {
index--;
Token token = recognizer.getTokenStream().get(index);
if (!token.getText().trim().isEmpty()) {
return token;
}
}
return recognizer.getCurrentToken();
&& (lastToken.isPresent() && !getSkipToTokenList().contains(lastToken.get()));
}

protected void consumeUntilNext(Parser recognizer, List<Integer> skipToTokenList) {
Expand All @@ -295,14 +196,10 @@ protected void consumeUntilNext(Parser recognizer, List<Integer> skipToTokenList
offendingToken,
offendingToken.getLine(),
offendingToken.getCharPositionInLine(),
messageService.getMessage("input.mismatch.skipAnalysis"),
this.getMessageService().getMessage("input.mismatch.skipAnalysis"),
new InputMismatchException(recognizer));
}
nextTokensContext = (ParserRuleContext) recognizer.getContext().parent;
nextTokensState = recognizer.getState();
}

private String getOffendingToken(InputMismatchException e) {
return getTokenErrorDisplay(e.getOffendingToken());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,11 @@
package org.eclipse.lsp.cobol.dialects.ibm.experimental;

import com.google.common.collect.ImmutableList;
import java.util.List;
import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor;
import org.antlr.v4.runtime.CharStreams;
import org.antlr.v4.runtime.DefaultErrorStrategy;
import org.antlr.v4.runtime.tree.ParseTreeListener;
import org.eclipse.lsp.cobol.common.dialects.DialectOutcome;
import org.eclipse.lsp.cobol.common.error.ErrorSeverity;
Expand All @@ -25,20 +28,17 @@
import org.eclipse.lsp.cobol.common.mapping.OriginalLocation;
import org.eclipse.lsp.cobol.common.message.MessageService;
import org.eclipse.lsp.cobol.common.model.tree.Node;
import org.eclipse.lsp.cobol.common.pipeline.Stage;
import org.eclipse.lsp.cobol.common.pipeline.StageResult;
import org.eclipse.lsp.cobol.core.*;
import org.eclipse.lsp.cobol.core.engine.analysis.AnalysisContext;
import org.eclipse.lsp.cobol.common.pipeline.StageResult;
import org.eclipse.lsp.cobol.common.pipeline.Stage;
import org.eclipse.lsp.cobol.core.strategy.CobolErrorStrategy;
import org.eclipse.lsp.cobol.core.strategy.BasicCobolErrorHandler;
import org.eclipse.lsp.cobol.core.visitor.ParserListener;
import org.eclipse.lsp.cobol.dialects.ibm.ParserStageResult;
import org.eclipse.lsp.cobol.parser.AstBuilder;
import org.eclipse.lsp.cobol.parser.SplitParser;
import org.eclipse.lsp4j.Location;

import java.util.List;
import java.util.stream.Collectors;

/**
* Parser stage
*/
Expand All @@ -56,7 +56,7 @@ public StageResult<ParserStageResult> run(AnalysisContext context, StageResult<D
.addAll(prevStageResult.getData().getDialectNodes())
.build());
ParserListener listener = new ParserListener(context.getExtendedDocument(), context.getCopybooksRepository());
CobolErrorStrategy errorStrategy = new CobolErrorStrategy(messageService);
DefaultErrorStrategy errorStrategy = new BasicCobolErrorHandler(messageService);
AstBuilder parser = new SplitParser(CharStreams.fromString(context.getExtendedDocument().toString()),
listener, errorStrategy, treeListener);
CobolParser.StartRuleContext tree = parser.runParser();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
import org.eclipse.lsp4j.Diagnostic;
import org.eclipse.lsp4j.DiagnosticSeverity;
import org.eclipse.lsp4j.Range;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
// to review

Expand Down Expand Up @@ -54,7 +53,6 @@ void test() {
}

@Test
@Disabled("EXPERIMENTAL_COBOL")
void testHw() {
UseCaseEngine.runTest(
TEXT,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
import org.eclipse.lsp4j.Diagnostic;
import org.eclipse.lsp4j.DiagnosticSeverity;
import org.eclipse.lsp4j.Range;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;

/** This test checks that unexpected text in ID DIVISION is flagged */
Expand All @@ -40,7 +39,6 @@ class TestHwUnexpectedTextInIdentificationDivision {
+ " DISPLAY {$VARNAME}.";

@Test
@Disabled("EXPERIMENTAL_COBOL")
void test() {
UseCaseEngine.runTest(
TEXT,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@
import org.eclipse.lsp4j.Diagnostic;
import org.eclipse.lsp4j.DiagnosticSeverity;
import org.eclipse.lsp4j.Range;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;

/** This use case checks the error shown if there is an unexpected symbol in the indicator area. */
Expand Down Expand Up @@ -51,7 +50,6 @@ void test() {
}

@Test
@Disabled("EXPERIMENTAL_COBOL")
void testHw() {
UseCaseEngine.runTest(
TEXT,
Expand Down
Loading

0 comments on commit ad09782

Please sign in to comment.