From d5ecf75e236e7619bbf8e2d3f70b9871e7a34ae8 Mon Sep 17 00:00:00 2001 From: volodya-lombrozo Date: Thu, 26 Dec 2024 16:31:52 +0300 Subject: [PATCH 1/6] feat(#3743): remove the puzzle for #3743 issue and write our excpectations --- .../org/eolang/parser/eo-typos/broken-binding.yaml | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/eo-parser/src/test/resources/org/eolang/parser/eo-typos/broken-binding.yaml b/eo-parser/src/test/resources/org/eolang/parser/eo-typos/broken-binding.yaml index 11a02f5b39..2fd50e41c2 100644 --- a/eo-parser/src/test/resources/org/eolang/parser/eo-typos/broken-binding.yaml +++ b/eo-parser/src/test/resources/org/eolang/parser/eo-typos/broken-binding.yaml @@ -21,11 +21,10 @@ # SOFTWARE. --- line: 4 -# @todo #3706:30min Add exact location of the error in the message. -# This message is already quite clear, but it would be better if it included -# the exact location of the error. message: |- - Object binding can't be negative + [4:4] error: 'Object binding can't be negative' + 42:-1 + ^ input: | # No comments [] > foo From c83ba897084673d58476a0fcce733d2fb7dbbd9f Mon Sep 17 00:00:00 2001 From: volodya-lombrozo Date: Thu, 26 Dec 2024 16:48:01 +0300 Subject: [PATCH 2/6] feat(#3743): use DrErrors instead of custom error handling --- .../org/eolang/parser/ParsingException.java | 9 ++ .../java/org/eolang/parser/XeEoListener.java | 105 +++++++++++++----- 2 files changed, 89 insertions(+), 25 deletions(-) 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 0182070258..e166d58d32 100644 --- a/eo-parser/src/main/java/org/eolang/parser/ParsingException.java +++ b/eo-parser/src/main/java/org/eolang/parser/ParsingException.java @@ -42,6 +42,15 @@ public final class ParsingException extends RuntimeException { */ private final int place; + /** + * Ctor. + * @param line The place + * @param msgs Messages + */ + ParsingException(final int line, final String... msgs) { + this(new IllegalStateException("Parsing error"), line, List.of(msgs)); + } + /** * Ctor. * @param cause Cause of failure diff --git a/eo-parser/src/main/java/org/eolang/parser/XeEoListener.java b/eo-parser/src/main/java/org/eolang/parser/XeEoListener.java index 9521158af6..bbdb99c792 100644 --- a/eo-parser/src/main/java/org/eolang/parser/XeEoListener.java +++ b/eo-parser/src/main/java/org/eolang/parser/XeEoListener.java @@ -25,6 +25,7 @@ import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; +import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; @@ -82,6 +83,8 @@ public final class XeEoListener implements EoListener, Iterable { */ private final Map errors; + private final List newerrors; + /** * Ctor. * @@ -91,6 +94,7 @@ public XeEoListener(final String name) { this.name = name; this.dirs = new Directives(); this.errors = new HashMap<>(0); + this.newerrors = new ArrayList<>(0); this.objects = new Objects.ObjXembly(); this.start = System.nanoTime(); } @@ -106,18 +110,33 @@ public void enterProgram(final EoParser.ProgramContext ctx) { @Override public void exitProgram(final EoParser.ProgramContext ctx) { this.dirs.xpath("/program").strict(1); - if (!this.errors.isEmpty()) { - this.dirs.addIf("errors").strict(1); - for (final Map.Entry error : this.errors.entrySet()) { - this.dirs - .add("error") - .attr("check", "eo-parser") - .attr("line", error.getKey().getStart().getLine()) - .attr("severity", "critical") - .set(error.getValue()); - } - this.dirs.up().up(); +// if (!this.errors.isEmpty()) { +// this.dirs.addIf("errors").strict(1); +// for (final Map.Entry error : this.errors.entrySet()) { +// this.dirs +// .add("error") +// .attr("check", "eo-parser") +// .attr("line", error.getKey().getStart().getLine()) +// .attr("severity", "critical") +// .set(error.getValue()); +// } +// this.dirs.up().up(); +// } + + if (!this.newerrors.isEmpty()) { + this.dirs.append(new DrErrors(this.newerrors)); +// this.dirs.addIf("errors").strict(1); +// for (final Map.Entry error : this.errors.entrySet()) { +// this.dirs +// .add("error") +// .attr("check", "eo-parser") +// .attr("line", error.getKey().getStart().getLine()) +// .attr("severity", "critical") +// .set(error.getValue()); +// } +// this.dirs.up().up(); } + this.dirs .attr("ms", (System.nanoTime() - this.start) / (1000L * 1000L)) .up(); @@ -483,12 +502,16 @@ public void exitHapplicationTailReversed(final EoParser.HapplicationTailReversed } @Override - public void enterHapplicationTailReversedFirst(final EoParser.HapplicationTailReversedFirstContext ctx) { + public void enterHapplicationTailReversedFirst( + final EoParser.HapplicationTailReversedFirstContext ctx + ) { this.objects.enter(); } @Override - public void exitHapplicationTailReversedFirst(final EoParser.HapplicationTailReversedFirstContext ctx) { + public void exitHapplicationTailReversedFirst( + final EoParser.HapplicationTailReversedFirstContext ctx + ) { this.objects.leave(); } @@ -573,12 +596,16 @@ public void exitVapplicationArgBound(final EoParser.VapplicationArgBoundContext } @Override - public void enterVapplicationArgBoundCurrent(final EoParser.VapplicationArgBoundCurrentContext ctx) { + public void enterVapplicationArgBoundCurrent( + final EoParser.VapplicationArgBoundCurrentContext ctx + ) { // Nothing here } @Override - public void exitVapplicationArgBoundCurrent(final EoParser.VapplicationArgBoundCurrentContext ctx) { + public void exitVapplicationArgBoundCurrent( + final EoParser.VapplicationArgBoundCurrentContext ctx + ) { // Nothing here } @@ -603,22 +630,30 @@ public void exitVapplicationArgUnbound(final EoParser.VapplicationArgUnboundCont } @Override - public void enterVapplicationArgUnboundCurrent(final EoParser.VapplicationArgUnboundCurrentContext ctx) { + public void enterVapplicationArgUnboundCurrent( + final EoParser.VapplicationArgUnboundCurrentContext ctx + ) { // Nothing here } @Override - public void exitVapplicationArgUnboundCurrent(final EoParser.VapplicationArgUnboundCurrentContext ctx) { + public void exitVapplicationArgUnboundCurrent( + final EoParser.VapplicationArgUnboundCurrentContext ctx + ) { // Nothing here } @Override - public void enterVapplicationArgUnboundNext(final EoParser.VapplicationArgUnboundNextContext ctx) { + public void enterVapplicationArgUnboundNext( + final EoParser.VapplicationArgUnboundNextContext ctx + ) { // Nothing here } @Override - public void exitVapplicationArgUnboundNext(final EoParser.VapplicationArgUnboundNextContext ctx) { + public void exitVapplicationArgUnboundNext( + final EoParser.VapplicationArgUnboundNextContext ctx + ) { // Nothing here } @@ -707,12 +742,16 @@ public void exitAttributesAs(final EoParser.AttributesAsContext ctx) { } @Override - public void enterVapplicationArgHanonymBoundBody(final EoParser.VapplicationArgHanonymBoundBodyContext ctx) { + public void enterVapplicationArgHanonymBoundBody( + final EoParser.VapplicationArgHanonymBoundBodyContext ctx + ) { // Nothing here } @Override - public void exitVapplicationArgHanonymBoundBody(final EoParser.VapplicationArgHanonymBoundBodyContext ctx) { + public void exitVapplicationArgHanonymBoundBody( + final EoParser.VapplicationArgHanonymBoundBodyContext ctx + ) { // Nothing here } @@ -865,12 +904,16 @@ public void exitMethodTailOptional(final EoParser.MethodTailOptionalContext ctx) } @Override - public void enterVmethodHeadApplicationTail(final EoParser.VmethodHeadApplicationTailContext ctx) { + public void enterVmethodHeadApplicationTail( + final EoParser.VmethodHeadApplicationTailContext ctx + ) { // Nothing here } @Override - public void exitVmethodHeadApplicationTail(final EoParser.VmethodHeadApplicationTailContext ctx) { + public void exitVmethodHeadApplicationTail( + final EoParser.VmethodHeadApplicationTailContext ctx + ) { // Nothing here } @@ -1040,7 +1083,13 @@ public void enterAs(final EoParser.AsContext ctx) { } else { final int index = Integer.parseInt(ctx.INT().getText()); if (index < 0) { - this.errors.put(ctx, "Object binding can't be negative"); + this.newerrors.add( + new ParsingException( + ctx.getStart().getLine(), + "Object binding can't be negative" + ) + ); +// this.errors.put(ctx, "Object binding can't be negative"); } has = String.format("α%d", index); } @@ -1095,7 +1144,13 @@ public void enterData(final EoParser.DataContext ctx) { } else { base = "unknown"; data = ctx::getText; - this.errors.put(ctx, String.format("Unknown data type: %s", ctx.getText())); + this.newerrors.add( + new ParsingException( + ctx.getStart().getLine(), + String.format("Unknown data type: %s", ctx.getText()) + ) + ); +// this.errors.put(ctx, String.format("Unknown data type: %s", ctx.getText())); } this.objects.prop("base", base).data(data.get()); } From 3ba98a06ec7ef6f8913556c42048c1d80cb3d458 Mon Sep 17 00:00:00 2001 From: volodya-lombrozo Date: Thu, 26 Dec 2024 17:08:16 +0300 Subject: [PATCH 3/6] feat(#3743): add more human-readable message to negative binding --- .../java/org/eolang/parser/XeEoListener.java | 26 +++++++++++++++++-- .../parser/eo-typos/broken-binding.yaml | 4 +-- 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/eo-parser/src/main/java/org/eolang/parser/XeEoListener.java b/eo-parser/src/main/java/org/eolang/parser/XeEoListener.java index bbdb99c792..c53bc372b1 100644 --- a/eo-parser/src/main/java/org/eolang/parser/XeEoListener.java +++ b/eo-parser/src/main/java/org/eolang/parser/XeEoListener.java @@ -32,8 +32,10 @@ import java.util.Map; import java.util.function.Supplier; import java.util.stream.Collectors; +import org.antlr.v4.runtime.CharStream; import org.antlr.v4.runtime.ParserRuleContext; import org.antlr.v4.runtime.Token; +import org.antlr.v4.runtime.misc.Interval; import org.antlr.v4.runtime.tree.ErrorNode; import org.antlr.v4.runtime.tree.TerminalNode; import org.apache.commons.text.StringEscapeUtils; @@ -1086,16 +1088,36 @@ public void enterAs(final EoParser.AsContext ctx) { this.newerrors.add( new ParsingException( ctx.getStart().getLine(), - "Object binding can't be negative" + new MsgLocated( + ctx.getStart().getLine(), + ctx.getStart().getCharPositionInLine(), + "Object binding can't be negative" + ).formatted(), + new MsgUnderlined( + this.line(ctx), + ctx.getStart().getCharPositionInLine(), + ctx.getText().length() + ).formatted() ) ); -// this.errors.put(ctx, "Object binding can't be negative"); } has = String.format("α%d", index); } this.objects.prop("as", has); } + private String line(ParserRuleContext ctx) { + final Token start1 = ctx.start; + final int lineNumber = start1.getLine(); + final CharStream stream = start1.getInputStream(); + String[] lines = stream.toString().split("\n"); + if (lineNumber > 0 && lineNumber <= lines.length) { + return lines[lineNumber - 1]; // Lines are 1-based + } else { + throw new IllegalArgumentException("Line number out of bounds"); + } + } + @Override public void exitAs(final EoParser.AsContext ctx) { this.objects.leave(); diff --git a/eo-parser/src/test/resources/org/eolang/parser/eo-typos/broken-binding.yaml b/eo-parser/src/test/resources/org/eolang/parser/eo-typos/broken-binding.yaml index 2fd50e41c2..36f02aca58 100644 --- a/eo-parser/src/test/resources/org/eolang/parser/eo-typos/broken-binding.yaml +++ b/eo-parser/src/test/resources/org/eolang/parser/eo-typos/broken-binding.yaml @@ -22,9 +22,9 @@ --- line: 4 message: |- - [4:4] error: 'Object binding can't be negative' + [4:6] error: 'Object binding can't be negative' 42:-1 - ^ + ^^^ input: | # No comments [] > foo From fe84ab5304eed7a2da0e35c12aa736db7ea12ce7 Mon Sep 17 00:00:00 2001 From: volodya-lombrozo Date: Thu, 26 Dec 2024 17:19:28 +0300 Subject: [PATCH 4/6] feat(#3743): remove redundant code --- .../java/org/eolang/parser/XeEoListener.java | 82 +++++++------------ 1 file changed, 30 insertions(+), 52 deletions(-) diff --git a/eo-parser/src/main/java/org/eolang/parser/XeEoListener.java b/eo-parser/src/main/java/org/eolang/parser/XeEoListener.java index c53bc372b1..b324a172cb 100644 --- a/eo-parser/src/main/java/org/eolang/parser/XeEoListener.java +++ b/eo-parser/src/main/java/org/eolang/parser/XeEoListener.java @@ -26,16 +26,12 @@ import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; import java.util.ArrayList; -import java.util.HashMap; import java.util.Iterator; import java.util.List; -import java.util.Map; import java.util.function.Supplier; import java.util.stream.Collectors; -import org.antlr.v4.runtime.CharStream; import org.antlr.v4.runtime.ParserRuleContext; import org.antlr.v4.runtime.Token; -import org.antlr.v4.runtime.misc.Interval; import org.antlr.v4.runtime.tree.ErrorNode; import org.antlr.v4.runtime.tree.TerminalNode; import org.apache.commons.text.StringEscapeUtils; @@ -81,11 +77,9 @@ public final class XeEoListener implements EoListener, Iterable { private final long start; /** - * Errors map. + * Errors. */ - private final Map errors; - - private final List newerrors; + private final List errors; /** * Ctor. @@ -95,8 +89,7 @@ public final class XeEoListener implements EoListener, Iterable { public XeEoListener(final String name) { this.name = name; this.dirs = new Directives(); - this.errors = new HashMap<>(0); - this.newerrors = new ArrayList<>(0); + this.errors = new ArrayList<>(0); this.objects = new Objects.ObjXembly(); this.start = System.nanoTime(); } @@ -112,33 +105,9 @@ public void enterProgram(final EoParser.ProgramContext ctx) { @Override public void exitProgram(final EoParser.ProgramContext ctx) { this.dirs.xpath("/program").strict(1); -// if (!this.errors.isEmpty()) { -// this.dirs.addIf("errors").strict(1); -// for (final Map.Entry error : this.errors.entrySet()) { -// this.dirs -// .add("error") -// .attr("check", "eo-parser") -// .attr("line", error.getKey().getStart().getLine()) -// .attr("severity", "critical") -// .set(error.getValue()); -// } -// this.dirs.up().up(); -// } - - if (!this.newerrors.isEmpty()) { - this.dirs.append(new DrErrors(this.newerrors)); -// this.dirs.addIf("errors").strict(1); -// for (final Map.Entry error : this.errors.entrySet()) { -// this.dirs -// .add("error") -// .attr("check", "eo-parser") -// .attr("line", error.getKey().getStart().getLine()) -// .attr("severity", "critical") -// .set(error.getValue()); -// } -// this.dirs.up().up(); + if (!this.errors.isEmpty()) { + this.dirs.append(new DrErrors(this.errors)); } - this.dirs .attr("ms", (System.nanoTime() - this.start) / (1000L * 1000L)) .up(); @@ -1085,7 +1054,7 @@ public void enterAs(final EoParser.AsContext ctx) { } else { final int index = Integer.parseInt(ctx.INT().getText()); if (index < 0) { - this.newerrors.add( + this.errors.add( new ParsingException( ctx.getStart().getLine(), new MsgLocated( @@ -1094,7 +1063,7 @@ public void enterAs(final EoParser.AsContext ctx) { "Object binding can't be negative" ).formatted(), new MsgUnderlined( - this.line(ctx), + XeEoListener.line(ctx), ctx.getStart().getCharPositionInLine(), ctx.getText().length() ).formatted() @@ -1106,18 +1075,6 @@ public void enterAs(final EoParser.AsContext ctx) { this.objects.prop("as", has); } - private String line(ParserRuleContext ctx) { - final Token start1 = ctx.start; - final int lineNumber = start1.getLine(); - final CharStream stream = start1.getInputStream(); - String[] lines = stream.toString().split("\n"); - if (lineNumber > 0 && lineNumber <= lines.length) { - return lines[lineNumber - 1]; // Lines are 1-based - } else { - throw new IllegalArgumentException("Line number out of bounds"); - } - } - @Override public void exitAs(final EoParser.AsContext ctx) { this.objects.leave(); @@ -1166,13 +1123,12 @@ public void enterData(final EoParser.DataContext ctx) { } else { base = "unknown"; data = ctx::getText; - this.newerrors.add( + this.errors.add( new ParsingException( ctx.getStart().getLine(), String.format("Unknown data type: %s", ctx.getText()) ) ); -// this.errors.put(ctx, String.format("Unknown data type: %s", ctx.getText())); } this.objects.prop("base", base).data(data.get()); } @@ -1274,4 +1230,26 @@ private static String trimMargin(final String text, final int indent) { } return res.toString(); } + + /** + * Get line from context. + * @param ctx Context + * @return Line + */ + private static String line(final ParserRuleContext ctx) { + final Token token = ctx.start; + final int number = token.getLine(); + final String[] lines = token.getInputStream().toString().split("\n"); + if (number > 0 && number <= lines.length) { + return lines[number - 1]; // Lines are 1-based + } else { + throw new IllegalArgumentException( + String.format( + "Line number '%s' out of bounds, total lines: %d", + number, + lines.length + ) + ); + } + } } From 9a11b5420cba16e54570881287483ca912a89634 Mon Sep 17 00:00:00 2001 From: volodya-lombrozo Date: Thu, 26 Dec 2024 17:41:09 +0300 Subject: [PATCH 5/6] feat(#3743): remove redundant code --- .../src/main/java/org/eolang/parser/XeEoListener.java | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/eo-parser/src/main/java/org/eolang/parser/XeEoListener.java b/eo-parser/src/main/java/org/eolang/parser/XeEoListener.java index b324a172cb..a4d46bdd1e 100644 --- a/eo-parser/src/main/java/org/eolang/parser/XeEoListener.java +++ b/eo-parser/src/main/java/org/eolang/parser/XeEoListener.java @@ -1112,7 +1112,7 @@ public void enterData(final EoParser.DataContext ctx) { text.substring(1, text.length() - 1) ).getBytes(StandardCharsets.UTF_8) ); - } else if (ctx.TEXT() != null) { + } else { base = "string"; final int indent = ctx.getStart().getCharPositionInLine(); data = new BytesToHex( @@ -1120,15 +1120,6 @@ public void enterData(final EoParser.DataContext ctx) { XeEoListener.trimMargin(text, indent) ).getBytes(StandardCharsets.UTF_8) ); - } else { - base = "unknown"; - data = ctx::getText; - this.errors.add( - new ParsingException( - ctx.getStart().getLine(), - String.format("Unknown data type: %s", ctx.getText()) - ) - ); } this.objects.prop("base", base).data(data.get()); } From 8bba15297d23b7f6d13d55d660460cc86a3e781b Mon Sep 17 00:00:00 2001 From: volodya-lombrozo Date: Thu, 26 Dec 2024 17:43:28 +0300 Subject: [PATCH 6/6] feat(#3743): remove unnecessary comment --- eo-parser/src/main/java/org/eolang/parser/XeEoListener.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eo-parser/src/main/java/org/eolang/parser/XeEoListener.java b/eo-parser/src/main/java/org/eolang/parser/XeEoListener.java index a4d46bdd1e..d848f9c976 100644 --- a/eo-parser/src/main/java/org/eolang/parser/XeEoListener.java +++ b/eo-parser/src/main/java/org/eolang/parser/XeEoListener.java @@ -1232,7 +1232,7 @@ private static String line(final ParserRuleContext ctx) { final int number = token.getLine(); final String[] lines = token.getInputStream().toString().split("\n"); if (number > 0 && number <= lines.length) { - return lines[number - 1]; // Lines are 1-based + return lines[number - 1]; } else { throw new IllegalArgumentException( String.format(