Skip to content

test: pass appropriate error handler for antlr adapter #2315

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
May 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading