diff --git a/eo-parser/src/main/java/org/eolang/parser/EoSyntax.java b/eo-parser/src/main/java/org/eolang/parser/EoSyntax.java index eaa3f250cf..301c34309c 100644 --- a/eo-parser/src/main/java/org/eolang/parser/EoSyntax.java +++ b/eo-parser/src/main/java/org/eolang/parser/EoSyntax.java @@ -38,6 +38,7 @@ import org.cactoos.text.Joined; import org.cactoos.text.Split; import org.cactoos.text.TextOf; +import org.eolang.parser.errors.EoParserErrors; import org.eolang.parser.errors.ParsingErrors; import org.xembly.Directives; import org.xembly.Xembler; @@ -114,17 +115,18 @@ public XML parsed() throws IOException { new CommonTokenStream(lexer) ); parser.removeErrorListeners(); - parser.addErrorListener(spy); + final EoParserErrors eospy = new EoParserErrors(lines); + parser.addErrorListener(eospy); final XeEoListener xel = new XeEoListener(this.name); new ParseTreeWalker().walk(xel, parser.program()); final XML dom = Syntax.CANONICAL.pass( new XMLDocument( new Xembler( - new Directives(xel).append(spy) + new Directives(xel).append(spy).append(eospy) ).domQuietly() ) ); - if (spy.size() == 0) { + if (spy.size() + eospy.size() == 0) { Logger.debug( this, "The %s program of %d EO lines compiled, no errors", @@ -133,7 +135,7 @@ public XML parsed() throws IOException { } else { Logger.debug( this, "The %s program of %d EO lines compiled with %d error(s)", - this.name, lines.size(), spy.size() + this.name, lines.size(), spy.size() + eospy.size() ); } return dom; diff --git a/eo-parser/src/main/java/org/eolang/parser/errors/EoParserErrors.java b/eo-parser/src/main/java/org/eolang/parser/errors/EoParserErrors.java index 9fc382a49d..d0f22ff7cf 100644 --- a/eo-parser/src/main/java/org/eolang/parser/errors/EoParserErrors.java +++ b/eo-parser/src/main/java/org/eolang/parser/errors/EoParserErrors.java @@ -1,12 +1,160 @@ +/* + * 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.errors; +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; +import org.antlr.v4.runtime.Parser; +import org.antlr.v4.runtime.RecognitionException; +import org.antlr.v4.runtime.Recognizer; +import org.antlr.v4.runtime.Token; +import org.cactoos.Text; +import org.eolang.parser.EoParser; +import org.eolang.parser.ParsingException; import org.xembly.Directive; +/** + * Accumulates all parsing errors related to EO parser. + * @since 0.50 + */ public final class EoParserErrors extends BaseErrorListener implements Iterable { + + /** + * Errors accumulated. + */ + private final List errors; + + /** + * The source. + */ + private final Lines lines; + + /** + * Ctor. + * @param src The source in lines + */ + public EoParserErrors(final List src) { + this(new ArrayList<>(0), new Lines(src)); + } + + /** + * Ctor. + * @param errors Errors accumulated + * @param lines The source in lines + */ + private EoParserErrors(final List errors, final Lines lines) { + this.errors = errors; + this.lines = lines; + } + + // @checkstyle ParameterNumberCheck (10 lines) + @Override + public void syntaxError( + final Recognizer recognizer, + final Object symbol, + final int line, + final int position, + final String msg, + final RecognitionException error + ) { + if (!Parser.class.isInstance(recognizer)) { + throw new IllegalArgumentException( + String.format( + "Illegal usage of %s, please use it to recognize only EO parser errors", this + ) + ); + } + if (error instanceof NoViableAltException || error instanceof InputMismatchException) { + final Token token = (Token) symbol; + final Parser parser = (Parser) recognizer; + final String rule = parser.getRuleInvocationStack().get(0); + final String[] names = parser.getRuleNames(); + final String detailed; + if (names[EoParser.RULE_objects].equals(rule)) { + detailed = "Invalid object declaration"; + } else if (names[EoParser.RULE_metas].equals(rule)) { + detailed = "Invalid meta declaration"; + } else if (names[EoParser.RULE_program].equals(rule)) { + detailed = "Invalid program declaration"; + } 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 + ) + ); + } else { + this.errors.add( + new ParsingException( + String.format( + "[%d:%d] %s: \"%s\"", + line, position, msg, this.lines.line(line) + ), + error, + line + ) + ); + } + } + @Override public Iterator iterator() { - return null; + return new ErrorDirectives(this.errors).iterator(); + } + + /** + * The number of errors. + * @return The number of errors. + */ + public int size() { + return this.errors.size(); } } diff --git a/eo-parser/src/main/java/org/eolang/parser/errors/ErrorDirectives.java b/eo-parser/src/main/java/org/eolang/parser/errors/ErrorDirectives.java index 41eb299287..b7d79fe763 100644 --- a/eo-parser/src/main/java/org/eolang/parser/errors/ErrorDirectives.java +++ b/eo-parser/src/main/java/org/eolang/parser/errors/ErrorDirectives.java @@ -1,3 +1,26 @@ +/* + * 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.errors; import java.util.Iterator; @@ -7,7 +30,11 @@ import org.xembly.Directive; import org.xembly.Directives; -public final class ErrorDirectives implements Iterable { +/** + * Error directives. + * @since 0.50 + */ +final class ErrorDirectives implements Iterable { /** * Errors accumulated. @@ -18,7 +45,7 @@ public final class ErrorDirectives implements Iterable { * Ctor. * @param errors The errors. */ - public ErrorDirectives(final List errors) { + ErrorDirectives(final List errors) { this.errors = errors; } diff --git a/eo-parser/src/main/java/org/eolang/parser/errors/Lines.java b/eo-parser/src/main/java/org/eolang/parser/errors/Lines.java index ca327d425d..b2a94926eb 100644 --- a/eo-parser/src/main/java/org/eolang/parser/errors/Lines.java +++ b/eo-parser/src/main/java/org/eolang/parser/errors/Lines.java @@ -1,3 +1,26 @@ +/* + * 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.errors; import java.util.List; @@ -5,6 +28,10 @@ import org.cactoos.Text; import org.cactoos.text.UncheckedText; +/** + * The source in lines. + * @since 0.50 + */ final class Lines { /** @@ -12,6 +39,10 @@ final class Lines { */ private final List lines; + /** + * Ctor. + * @param lines The source in lines + */ Lines(final List lines) { this.lines = lines; } @@ -21,7 +52,7 @@ final class Lines { * @param number The line number. * @return The line. */ - Optional line(final int number) { + String line(final int number) { final Optional result; if (number < 1 || number > this.lines.size()) { result = Optional.empty(); @@ -30,6 +61,6 @@ Optional line(final int number) { .map(UncheckedText::new) .map(UncheckedText::asString); } - return result; + return result.orElse("EOF"); } } diff --git a/eo-parser/src/main/java/org/eolang/parser/errors/ParsingErrors.java b/eo-parser/src/main/java/org/eolang/parser/errors/ParsingErrors.java index 786ad35a43..e0e0d82a23 100644 --- a/eo-parser/src/main/java/org/eolang/parser/errors/ParsingErrors.java +++ b/eo-parser/src/main/java/org/eolang/parser/errors/ParsingErrors.java @@ -23,20 +23,14 @@ */ package org.eolang.parser.errors; +import java.util.ArrayList; import java.util.Iterator; -import java.util.LinkedList; 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; -import org.antlr.v4.runtime.Parser; import org.antlr.v4.runtime.RecognitionException; import org.antlr.v4.runtime.Recognizer; -import org.antlr.v4.runtime.Token; import org.cactoos.Text; import org.cactoos.list.ListOf; -import org.eolang.parser.EoParser; import org.eolang.parser.ParsingException; import org.xembly.Directive; @@ -70,8 +64,17 @@ public ParsingErrors(final Text... lines) { * @param src The source in lines */ public ParsingErrors(final List src) { - this.errors = new LinkedList<>(); - this.lines = new Lines(src); + this(new ArrayList<>(0), new Lines(src)); + } + + /** + * Ctor. + * @param errors Errors accumulated + * @param lines The source in lines + */ + private ParsingErrors(final List errors, final Lines lines) { + this.errors = errors; + this.lines = lines; } // @checkstyle ParameterNumberCheck (10 lines) @@ -84,59 +87,16 @@ public void syntaxError( final String msg, final RecognitionException error ) { - if (error instanceof NoViableAltException || error instanceof InputMismatchException) { - final Token token = (Token) symbol; - final Parser parser = (Parser) recognizer; - final String rule = parser.getRuleInvocationStack().get(0); - final String[] names = parser.getRuleNames(); - final String detailed; - if (names[EoParser.RULE_objects].equals(rule)) { - detailed = "Invalid object declaration"; - } else if (names[EoParser.RULE_metas].equals(rule)) { - detailed = "Invalid meta declaration"; - } else if (names[EoParser.RULE_program].equals(rule)) { - detailed = "Invalid program declaration"; - } 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).orElse("EOF"), - 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 - ) - ); - } else { - this.errors.add( - new ParsingException( - String.format( - "[%d:%d] %s: \"%s\"", - line, position, msg, this.lines.line(line).orElse("EOF") - ), - error, - line - ) - ); - } + this.errors.add( + new ParsingException( + String.format( + "[%d:%d] %s: \"%s\"", + line, position, msg, this.lines.line(line) + ), + error, + line + ) + ); } @Override diff --git a/eo-parser/src/main/java/org/eolang/parser/errors/package-info.java b/eo-parser/src/main/java/org/eolang/parser/errors/package-info.java new file mode 100644 index 0000000000..fb73a69d54 --- /dev/null +++ b/eo-parser/src/main/java/org/eolang/parser/errors/package-info.java @@ -0,0 +1,28 @@ +/* + * 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. + */ +/** + * This package contains all the classes related to errors that can be found in the parsing process. + * @since 0.50 + */ +package org.eolang.parser.errors; \ No newline at end of file