diff --git a/eo-parser/src/main/java/org/eolang/parser/EoParserErrors.java b/eo-parser/src/main/java/org/eolang/parser/EoParserErrors.java index aa9dc9d463..2b061e11f6 100644 --- a/eo-parser/src/main/java/org/eolang/parser/EoParserErrors.java +++ b/eo-parser/src/main/java/org/eolang/parser/EoParserErrors.java @@ -26,7 +26,6 @@ import java.util.ArrayList; import java.util.Iterator; import java.util.List; -import java.util.Objects; import org.antlr.v4.runtime.BaseErrorListener; import org.antlr.v4.runtime.InputMismatchException; import org.antlr.v4.runtime.NoViableAltException; @@ -87,6 +86,7 @@ public void syntaxError( ) ); } + final List msgs = new ArrayList<>(0); if (error instanceof NoViableAltException || error instanceof InputMismatchException) { final Token token = (Token) symbol; final Parser parser = (Parser) recognizer; @@ -102,44 +102,19 @@ public void syntaxError( } else { detailed = "no viable alternative at input"; } - this.errors.add( - new ParsingException( - String.format( - "[%d:%d] %s: %s:%n%s", - line, position, - "error", - detailed, - new UnderlinedMessage( - this.lines.line(line), - position, - Math.max(token.getStopIndex() - token.getStartIndex(), 1) - ).formatted() - ), - error, - line - ) - ); - } else if (Objects.isNull(error)) { - this.errors.add( - new ParsingException( - String.format( - "[%d:%d] %s: %s", line, position, "error", msg - ), - line - ) + msgs.add(new MsgLocated(line, position, detailed).formatted()); + msgs.add( + new MsgUnderlined( + this.lines.line(line), + position, + Math.max(token.getStopIndex() - token.getStartIndex(), 1) + ).formatted() ); } else { - this.errors.add( - new ParsingException( - String.format( - "[%d:%d] %s: \"%s\"", - line, position, msg, this.lines.line(line) - ), - error, - line - ) - ); + msgs.add(new MsgLocated(line, position, msg).formatted()); + msgs.add(this.lines.line(line)); } + this.errors.add(new ParsingException(error, line, msgs)); } @Override diff --git a/eo-parser/src/main/java/org/eolang/parser/GeneralErrors.java b/eo-parser/src/main/java/org/eolang/parser/GeneralErrors.java index 8c765869c7..e66eba9eff 100644 --- a/eo-parser/src/main/java/org/eolang/parser/GeneralErrors.java +++ b/eo-parser/src/main/java/org/eolang/parser/GeneralErrors.java @@ -87,12 +87,10 @@ public void syntaxError( ) { this.errors.add( new ParsingException( - String.format( - "[%d:%d] %s: \"%s\"", - line, position, msg, this.lines.line(line) - ), error, - line + line, + new MsgLocated(line, position, msg).formatted(), + this.lines.line(line) ) ); } diff --git a/eo-parser/src/main/java/org/eolang/parser/MsgLocated.java b/eo-parser/src/main/java/org/eolang/parser/MsgLocated.java new file mode 100644 index 0000000000..1191b60a9e --- /dev/null +++ b/eo-parser/src/main/java/org/eolang/parser/MsgLocated.java @@ -0,0 +1,66 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2016-2024 Objectionary.com + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package org.eolang.parser; + +/** + * Error message that includes the location of the error. + * @since 0.50 + */ +final class MsgLocated { + + /** + * The line where the error occurred. + */ + private final int line; + + /** + * The position in the line where the error occurred. + */ + private final int position; + + /** + * The error message. + */ + private final String message; + + /** + * Ctor. + * @param line The line where the error occurred. + * @param position The position in the line where the error occurred. + * @param message The error message. + */ + MsgLocated(final int line, final int position, final String message) { + this.line = line; + this.position = position; + this.message = message; + } + + /** + * Formats the error message. + * @return The formatted error message. + */ + String formatted() { + return String.format("[%d:%d] error: '%s'", this.line, this.position, this.message); + } +} diff --git a/eo-parser/src/main/java/org/eolang/parser/UnderlinedMessage.java b/eo-parser/src/main/java/org/eolang/parser/MsgUnderlined.java similarity index 84% rename from eo-parser/src/main/java/org/eolang/parser/UnderlinedMessage.java rename to eo-parser/src/main/java/org/eolang/parser/MsgUnderlined.java index a6f3a3ce2b..284fc4928b 100644 --- a/eo-parser/src/main/java/org/eolang/parser/UnderlinedMessage.java +++ b/eo-parser/src/main/java/org/eolang/parser/MsgUnderlined.java @@ -40,11 +40,8 @@ * } *

* @since 0.50 - * @todo #3332:30min Add more decorators for the error message. - * For example, {@link GeneralErrors} currently contains logic related to the message formatting. - * It's better to create a separate class for this purpose. */ -final class UnderlinedMessage { +final class MsgUnderlined { /** * The message. @@ -67,7 +64,7 @@ final class UnderlinedMessage { * @param from The position from which to start underlining. * @param length The length of the underline. */ - UnderlinedMessage(final String origin, final int from, final int length) { + MsgUnderlined(final String origin, final int from, final int length) { this.origin = origin; this.from = from; this.length = length; @@ -94,12 +91,12 @@ private String underline() { if (this.origin.isEmpty() || this.length <= 0 || this.from >= this.origin.length()) { result = ""; } else if (this.from < 0) { - result = UnderlinedMessage.repeat("^", this.origin.length()); + result = MsgUnderlined.repeat("^", this.origin.length()); } else { result = String.format( "%s%s", - UnderlinedMessage.repeat(" ", this.from), - UnderlinedMessage.repeat("^", Math.min(this.length, this.origin.length())) + MsgUnderlined.repeat(" ", this.from), + MsgUnderlined.repeat("^", Math.min(this.length, this.origin.length())) ); } return result; diff --git a/eo-parser/src/main/java/org/eolang/parser/ParsingException.java b/eo-parser/src/main/java/org/eolang/parser/ParsingException.java index 857019b306..0182070258 100644 --- a/eo-parser/src/main/java/org/eolang/parser/ParsingException.java +++ b/eo-parser/src/main/java/org/eolang/parser/ParsingException.java @@ -23,6 +23,8 @@ */ package org.eolang.parser; +import java.util.List; + /** * When parsing fails. * @@ -42,20 +44,34 @@ public final class ParsingException extends RuntimeException { /** * Ctor. - * @param msg Message + * @param cause Cause of failure * @param line The place + * @param msgs Messages */ - public ParsingException(final String msg, final int line) { - this(msg, null, line); + ParsingException(final Exception cause, final int line, final String... msgs) { + this(cause, line, List.of(msgs)); } /** * Ctor. - * @param msg Message + * + * @param cause The cause + * @param line The place + * @param msgs Messages + * @since 0.1 + */ + ParsingException(final Exception cause, final int line, final List msgs) { + this(cause, line, String.join("\n", msgs)); + } + + /** + * Ctor. + * * @param cause Cause of failure * @param line The place + * @param msg Message */ - public ParsingException(final String msg, final Exception cause, final int line) { + ParsingException(final Exception cause, final int line, final String msg) { super(msg, cause); this.place = line; } @@ -67,5 +83,4 @@ public ParsingException(final String msg, final Exception cause, final int line) public int line() { return this.place; } - } diff --git a/eo-parser/src/main/java/org/eolang/parser/XePhiListener.java b/eo-parser/src/main/java/org/eolang/parser/XePhiListener.java index 4ed05bc80e..edad339442 100644 --- a/eo-parser/src/main/java/org/eolang/parser/XePhiListener.java +++ b/eo-parser/src/main/java/org/eolang/parser/XePhiListener.java @@ -298,9 +298,8 @@ public void enterDeltaBinding(final PhiParser.DeltaBindingContext ctx) { && !"bytes".equals(this.attributes.peek()) ) { throw new ParsingException( - "It's impossible to represent Δ ⤍ ∅ binding in EO", - new IllegalStateException(), - ctx.getStart().getLine() + new IllegalStateException(), ctx.getStart().getLine(), + "It's impossible to represent Δ ⤍ ∅ binding in EO" ); } } else { diff --git a/eo-parser/src/test/java/org/eolang/parser/UnderlinedMessageTest.java b/eo-parser/src/test/java/org/eolang/parser/MsgUnderlinedTest.java similarity index 93% rename from eo-parser/src/test/java/org/eolang/parser/UnderlinedMessageTest.java rename to eo-parser/src/test/java/org/eolang/parser/MsgUnderlinedTest.java index f7b2215c3d..a3721448d6 100644 --- a/eo-parser/src/test/java/org/eolang/parser/UnderlinedMessageTest.java +++ b/eo-parser/src/test/java/org/eolang/parser/MsgUnderlinedTest.java @@ -31,25 +31,25 @@ import org.junit.jupiter.params.provider.MethodSource; /** - * Test case for {@link UnderlinedMessage}. + * Test case for {@link MsgUnderlined}. * @since 0.50 * @checkstyle ParameterNumberCheck (500 lines) */ @SuppressWarnings("PMD.AvoidDuplicateLiterals") -final class UnderlinedMessageTest { +final class MsgUnderlinedTest { @ParameterizedTest @MethodSource("examples") void addsUndeline(final String input, final int from, final int length, final String expected) { MatcherAssert.assertThat( "We expect the message to be highlighted with underline characters", - new UnderlinedMessage(input, from, length).formatted(), + new MsgUnderlined(input, from, length).formatted(), Matchers.equalTo(expected) ); } /** - * Test cases for {@link UnderlinedMessageTest#addsUndeline}. + * Test cases for {@link MsgUnderlinedTest#addsUndeline}. * ANTLR {@link org.antlr.v4.runtime.BaseErrorListener} returns strange line numbers * and positions like -1. Here I hide this problem intentionally to make all the rest * tests pass. diff --git a/eo-parser/src/test/resources/org/eolang/parser/eo-typos/binding-with-rho.yaml b/eo-parser/src/test/resources/org/eolang/parser/eo-typos/binding-with-rho.yaml index cdfb53e8dc..e26648c246 100644 --- a/eo-parser/src/test/resources/org/eolang/parser/eo-typos/binding-with-rho.yaml +++ b/eo-parser/src/test/resources/org/eolang/parser/eo-typos/binding-with-rho.yaml @@ -22,7 +22,7 @@ --- line: 2 message: >- - [2:4] error: Invalid object declaration: + [2:4] error: 'Invalid object declaration' y:^ ^ input: | diff --git a/eo-parser/src/test/resources/org/eolang/parser/eo-typos/broken-head.yaml b/eo-parser/src/test/resources/org/eolang/parser/eo-typos/broken-head.yaml index f3c36fb615..6fd20024e8 100644 --- a/eo-parser/src/test/resources/org/eolang/parser/eo-typos/broken-head.yaml +++ b/eo-parser/src/test/resources/org/eolang/parser/eo-typos/broken-head.yaml @@ -22,7 +22,7 @@ --- line: 2 message: |- - [2:7] error: Invalid object declaration: + [2:7] error: 'Invalid object declaration' [] > a [] > b [] > c [] > d hello world ^ input: | diff --git a/eo-parser/src/test/resources/org/eolang/parser/eo-typos/comment-in-method.yaml b/eo-parser/src/test/resources/org/eolang/parser/eo-typos/comment-in-method.yaml index faf260bb1d..a23d4d38a9 100644 --- a/eo-parser/src/test/resources/org/eolang/parser/eo-typos/comment-in-method.yaml +++ b/eo-parser/src/test/resources/org/eolang/parser/eo-typos/comment-in-method.yaml @@ -25,7 +25,7 @@ line: 5 # comment. The error message should be updated to point to the exact position # of the comment. message: | - [5:12] error: Invalid object declaration: + [5:12] error: 'Invalid object declaration' sprintwf input: | # No comments diff --git a/eo-parser/src/test/resources/org/eolang/parser/eo-typos/double-empty-lines.yaml b/eo-parser/src/test/resources/org/eolang/parser/eo-typos/double-empty-lines.yaml index bb01c11031..49c788c005 100644 --- a/eo-parser/src/test/resources/org/eolang/parser/eo-typos/double-empty-lines.yaml +++ b/eo-parser/src/test/resources/org/eolang/parser/eo-typos/double-empty-lines.yaml @@ -25,8 +25,9 @@ line: 4 # Cryptic error message is returned when there are two empty lines between metas. # The error message should be more informative and should highlight the exact location # of the error. -message: |- - [4:0] error: extraneous input '\n' expecting {COMMENTARY, 'Q', 'QQ', '*', '$', '[', '(', '@', '^', BYTES, STRING, INT, FLOAT, HEX, NAME, TEXT} +message: | + [4:0] error: 'extraneous input '\n' expecting {COMMENTARY, 'Q', 'QQ', '*', '$', '[', '(', '@', '^', BYTES, STRING, INT, FLOAT, HEX, NAME, TEXT}' + input: | # No comments. [args] > one diff --git a/eo-parser/src/test/resources/org/eolang/parser/eo-typos/double-space-in-meta.yaml b/eo-parser/src/test/resources/org/eolang/parser/eo-typos/double-space-in-meta.yaml index f5bb2547d5..7778e2776a 100644 --- a/eo-parser/src/test/resources/org/eolang/parser/eo-typos/double-space-in-meta.yaml +++ b/eo-parser/src/test/resources/org/eolang/parser/eo-typos/double-space-in-meta.yaml @@ -22,7 +22,7 @@ --- line: 1 message: |- - [1:10] error: Invalid meta declaration: + [1:10] error: 'Invalid meta declaration' +meta with spaces ^ input: | diff --git a/eo-parser/src/test/resources/org/eolang/parser/eo-typos/empty-line-between-metas.yaml b/eo-parser/src/test/resources/org/eolang/parser/eo-typos/empty-line-between-metas.yaml index 73f0384a54..0e3cd9dd96 100644 --- a/eo-parser/src/test/resources/org/eolang/parser/eo-typos/empty-line-between-metas.yaml +++ b/eo-parser/src/test/resources/org/eolang/parser/eo-typos/empty-line-between-metas.yaml @@ -22,7 +22,7 @@ --- line: 3 message: |- - [3:0] error: Invalid object declaration: + [3:0] error: 'Invalid object declaration' +meta other ^^^^^^^^^^ input: | diff --git a/eo-parser/src/test/resources/org/eolang/parser/eo-typos/missing-empty-line-after-metas.yaml b/eo-parser/src/test/resources/org/eolang/parser/eo-typos/missing-empty-line-after-metas.yaml index 44ca6879e9..51da52a793 100644 --- a/eo-parser/src/test/resources/org/eolang/parser/eo-typos/missing-empty-line-after-metas.yaml +++ b/eo-parser/src/test/resources/org/eolang/parser/eo-typos/missing-empty-line-after-metas.yaml @@ -22,7 +22,7 @@ --- line: 3 message: |- - [3:0] error: Invalid meta declaration: + [3:0] error: 'Invalid meta declaration' [] > main ^ input: | diff --git a/eo-parser/src/test/resources/org/eolang/parser/eo-typos/not-empty-atoms.yaml b/eo-parser/src/test/resources/org/eolang/parser/eo-typos/not-empty-atoms.yaml index db8dd4a130..1dc5a41adf 100644 --- a/eo-parser/src/test/resources/org/eolang/parser/eo-typos/not-empty-atoms.yaml +++ b/eo-parser/src/test/resources/org/eolang/parser/eo-typos/not-empty-atoms.yaml @@ -22,7 +22,7 @@ --- line: 4 message: |- - [4:-1] error: Invalid program declaration: + [4:-1] error: 'Invalid program declaration' [] > inner ^^^^^^^^^^^^ input: | diff --git a/eo-parser/src/test/resources/org/eolang/parser/eo-typos/redundant-parentheses/simple-application-named.yaml b/eo-parser/src/test/resources/org/eolang/parser/eo-typos/redundant-parentheses/simple-application-named.yaml index 410ff63447..c39d735c6c 100644 --- a/eo-parser/src/test/resources/org/eolang/parser/eo-typos/redundant-parentheses/simple-application-named.yaml +++ b/eo-parser/src/test/resources/org/eolang/parser/eo-typos/redundant-parentheses/simple-application-named.yaml @@ -22,7 +22,7 @@ --- line: 3 message: |- - [3:-1] error: Invalid program declaration: + [3:-1] error: 'Invalid program declaration' EOF ^^^ input: | diff --git a/eo-parser/src/test/resources/org/eolang/parser/eo-typos/redundant-parentheses/simple-application.yaml b/eo-parser/src/test/resources/org/eolang/parser/eo-typos/redundant-parentheses/simple-application.yaml index f7c3882170..19c8ed8c72 100644 --- a/eo-parser/src/test/resources/org/eolang/parser/eo-typos/redundant-parentheses/simple-application.yaml +++ b/eo-parser/src/test/resources/org/eolang/parser/eo-typos/redundant-parentheses/simple-application.yaml @@ -27,7 +27,7 @@ line: 3 # place in the input where the error occurred. Moreover it should be clear # what to do to fix the error. 'simple-application-named.yaml' has the same issue. message: |- - [3:-1] error: Invalid program declaration: + [3:-1] error: 'Invalid program declaration' EOF ^^^ input: | diff --git a/eo-parser/src/test/resources/org/eolang/parser/eo-typos/two-spaces.yaml b/eo-parser/src/test/resources/org/eolang/parser/eo-typos/two-spaces.yaml index 7c1dbb50ab..f6ceb95e1a 100644 --- a/eo-parser/src/test/resources/org/eolang/parser/eo-typos/two-spaces.yaml +++ b/eo-parser/src/test/resources/org/eolang/parser/eo-typos/two-spaces.yaml @@ -22,7 +22,7 @@ --- line: 5 message: >- - [5:2] error: Invalid object declaration: + [5:2] error: 'Invalid object declaration' * ^ input: | diff --git a/eo-parser/src/test/resources/org/eolang/parser/eo-typos/vmethod-after-happlication.yaml b/eo-parser/src/test/resources/org/eolang/parser/eo-typos/vmethod-after-happlication.yaml index fcd162a8a6..5511460fc4 100644 --- a/eo-parser/src/test/resources/org/eolang/parser/eo-typos/vmethod-after-happlication.yaml +++ b/eo-parser/src/test/resources/org/eolang/parser/eo-typos/vmethod-after-happlication.yaml @@ -22,7 +22,7 @@ --- line: 2 message: |- - [2:0] error: Invalid program declaration: + [2:0] error: 'Invalid program declaration' .z ^ input: | diff --git a/eo-parser/src/test/resources/org/eolang/parser/eo-typos/vmethod-after-hmethod.yaml b/eo-parser/src/test/resources/org/eolang/parser/eo-typos/vmethod-after-hmethod.yaml index d76fb3a8b8..8dfac16a58 100644 --- a/eo-parser/src/test/resources/org/eolang/parser/eo-typos/vmethod-after-hmethod.yaml +++ b/eo-parser/src/test/resources/org/eolang/parser/eo-typos/vmethod-after-hmethod.yaml @@ -22,7 +22,7 @@ --- line: 2 message: |- - [2:0] error: Invalid program declaration: + [2:0] error: 'Invalid program declaration' .z ^ input: |