From 9fbba868dac37f479fd8a993e2e906d9041a9ac6 Mon Sep 17 00:00:00 2001 From: JFronny Date: Tue, 18 Apr 2023 14:54:39 +0200 Subject: [PATCH] clean up exception pretty printing --- .../jfronny/muscript/compiler/Lexer.java | 4 ++ .../jfronny/muscript/compiler/Parser.java | 20 +++---- .../muscript/error/LocationalException.java | 17 ++++-- ...tionalError.java => PrettyPrintError.java} | 52 +++---------------- 4 files changed, 33 insertions(+), 60 deletions(-) rename muscript/src/main/java/io/gitlab/jfronny/muscript/error/{LocationalError.java => PrettyPrintError.java} (69%) diff --git a/muscript/src/main/java/io/gitlab/jfronny/muscript/compiler/Lexer.java b/muscript/src/main/java/io/gitlab/jfronny/muscript/compiler/Lexer.java index e87bb63..7140b36 100644 --- a/muscript/src/main/java/io/gitlab/jfronny/muscript/compiler/Lexer.java +++ b/muscript/src/main/java/io/gitlab/jfronny/muscript/compiler/Lexer.java @@ -31,6 +31,10 @@ public class Lexer { this.file = file; } + public CodeLocation location() { + return new CodeLocation(start, current - 1, source, file); + } + /** * Scans for the next token storing it in {@link Lexer#token} and {@link Lexer#lexeme}. Produces {@link Token#EOF} if the end of source code has been reached and {@link Token#Error} if there has been an error */ diff --git a/muscript/src/main/java/io/gitlab/jfronny/muscript/compiler/Parser.java b/muscript/src/main/java/io/gitlab/jfronny/muscript/compiler/Parser.java index 9123a24..0f04a0a 100644 --- a/muscript/src/main/java/io/gitlab/jfronny/muscript/compiler/Parser.java +++ b/muscript/src/main/java/io/gitlab/jfronny/muscript/compiler/Parser.java @@ -16,7 +16,6 @@ import io.gitlab.jfronny.muscript.error.*; import org.jetbrains.annotations.Nullable; import java.util.*; -import java.util.stream.Collectors; public class Parser { private final Lexer lexer; @@ -63,8 +62,8 @@ public class Parser { includes.addAll(parseMultiScript(file, filesystem, alreadyIncluded)); } } else { - throw new ParseException(LocationalError.builder() - .setLocation(new LocationalError.Location(s, 0, row), new LocationalError.Location(s, s.length() - 1, row)) + throw new ParseException(PrettyPrintError.builder() + .setLocation(new PrettyPrintError.Location(s, 0, row), new PrettyPrintError.Location(s, s.length() - 1, row)) .setMessage("Includes MUST be located at the top of the file") .build()); } @@ -91,7 +90,7 @@ public class Parser { advance(); Expr expr = expression(); if (!isAtEnd()) - throw new ParseException(LocationalError.create(lexer.source, lexer.start, lexer.current - 1, "Unexpected element after end of expression")); + throw new ParseException(PrettyPrintError.builder(lexer.location()).setMessage("Unexpected element after end of expression").build()); return expr; } @@ -108,7 +107,7 @@ public class Parser { expressions.add(expression()); match(Token.Semicolon); // Consume semicolon if present } - if (expressions.isEmpty()) throw new ParseException(LocationalError.create(lexer.source, lexer.start, lexer.current - 1, "Missing any elements in closure")); + if (expressions.isEmpty()) throw new ParseException(PrettyPrintError.builder(lexer.location()).setMessage("Missing any elements in closure").build()); return new Script(expressions); } @@ -434,11 +433,12 @@ public class Parser { } private ParseException error(String message) { - return new ParseException(LocationalError.create(lexer.source, current.current - 1, message)); + int loc = current.current - 1; + return new ParseException(PrettyPrintError.builder(location(loc, loc)).setMessage(message).build()); } private ParseException error(String message, Expr expr) { - return new ParseException(LocationalError.create(expr.location, message)); + return new ParseException(PrettyPrintError.builder(expr.location).setMessage(message).build()); } private TokenData consume(Token token, String message) { @@ -510,14 +510,14 @@ public class Parser { // Parse Exception public static class ParseException extends RuntimeException { - public final LocationalError error; + public final PrettyPrintError error; - public ParseException(LocationalError error) { + public ParseException(PrettyPrintError error) { super(error.toString()); this.error = error; } - public ParseException(LocationalError error, Throwable cause) { + public ParseException(PrettyPrintError error, Throwable cause) { super(error.toString(), cause); this.error = error; } diff --git a/muscript/src/main/java/io/gitlab/jfronny/muscript/error/LocationalException.java b/muscript/src/main/java/io/gitlab/jfronny/muscript/error/LocationalException.java index 297b6f3..bf17d0d 100644 --- a/muscript/src/main/java/io/gitlab/jfronny/muscript/error/LocationalException.java +++ b/muscript/src/main/java/io/gitlab/jfronny/muscript/error/LocationalException.java @@ -13,6 +13,8 @@ public class LocationalException extends RuntimeException { private final CodeLocation location; private final List callStack = new LinkedList<>(); + private String messageCache; + public LocationalException(CodeLocation location) { super(); this.location = location; @@ -33,16 +35,21 @@ public class LocationalException extends RuntimeException { this.location = location; } - public LocationalError asPrintable() { - return LocationalError.builder() - .setSource(location.source()) - .setLocation(location.chStart(), location.chEnd()) - .setMessage(getLocalizedMessage()) + @Override + public String getLocalizedMessage() { + // Not getMessage() to fix locations + return messageCache != null ? messageCache : (messageCache = asPrintable().toString()); + } + + public PrettyPrintError asPrintable() { + return PrettyPrintError.builder(location) + .setMessage(super.getMessage()) .setCallStack(callStack) .build(); } public LocationalException appendStack(StackFrame frame) { + messageCache = null; callStack.add(frame); return this; } diff --git a/muscript/src/main/java/io/gitlab/jfronny/muscript/error/LocationalError.java b/muscript/src/main/java/io/gitlab/jfronny/muscript/error/PrettyPrintError.java similarity index 69% rename from muscript/src/main/java/io/gitlab/jfronny/muscript/error/LocationalError.java rename to muscript/src/main/java/io/gitlab/jfronny/muscript/error/PrettyPrintError.java index 9d1cfed..036a603 100644 --- a/muscript/src/main/java/io/gitlab/jfronny/muscript/error/LocationalError.java +++ b/muscript/src/main/java/io/gitlab/jfronny/muscript/error/PrettyPrintError.java @@ -5,8 +5,6 @@ import org.jetbrains.annotations.Nullable; import java.util.*; -//TODO maybe this can be eliminated since the source is now included? - /** * Class for storing errors with code context * Can be generated from a LocationalException with asPrintable @@ -15,11 +13,7 @@ import java.util.*; * @param start The location of the start of this error. Both it and its components must not be null. * @param end The location of the end of this error. May be null. */ -public record LocationalError(String message, Location start, @Nullable Location end, List callStack) { - public LocationalError(String message, Location start, @Nullable Location end) { - this(message, start, end, List.of()); - } - +public record PrettyPrintError(String message, Location start, @Nullable Location end, List callStack) { /** * A location in the source code * @@ -54,42 +48,6 @@ public record LocationalError(String message, Location start, @Nullable Location } } - /** - * Generates an error by getting the relevant data from what is available while lexing/parsing - * - * @param source The complete source for the code that generated this error - * @param start The index of the start of the expression that caused this error - * @param message The error message - * @return An error using the provided information - */ - public static LocationalError create(String source, int start, String message) { - return builder().setSource(source).setLocation(start).setMessage(message).build(); - } - - /** - * Generates an error by getting the relevant data from what is available while lexing/parsing - * - * @param source The complete source for the code that generated this error - * @param start The index of the start of the expression that caused this error - * @param end The index of the end of the expression that caused this error - * @param message The error message - * @return An error using the provided information - */ - public static LocationalError create(String source, int start, int end, String message) { - return builder().setSource(source).setLocation(start, end).setMessage(message).build(); - } - - /** - * Generates an error by getting the relevant data from what is available while lexing/parsing - * - * @param location The location of the piece of code causing this - * @param message The error message - * @return An error using the provided information - */ - public static LocationalError create(CodeLocation location, String message) { - return builder().setSource(location.source()).setLocation(location.chStart(), location.chEnd()).setMessage(message).build(); - } - /** * Converts this error to a human-readable error message * @@ -116,6 +74,10 @@ public record LocationalError(String message, Location start, @Nullable Location return new Builder(); } + public static Builder builder(CodeLocation location) { + return builder().setSource(location.source()).setLocation(location.chStart(), location.chEnd()); + } + public static class Builder { private String message; private Location start; @@ -163,8 +125,8 @@ public record LocationalError(String message, Location start, @Nullable Location return this; } - public LocationalError build() { - return new LocationalError(message, start, end, callStack); + public PrettyPrintError build() { + return new PrettyPrintError(message, start, end, callStack); } } }