101 lines
4.2 KiB
Java
101 lines
4.2 KiB
Java
package io.gitlab.jfronny.muscript.error;
|
|
|
|
import org.jetbrains.annotations.Nullable;
|
|
|
|
/**
|
|
* Class for storing errors with code context
|
|
* Can be generated from a LocationalException with asPrintable
|
|
*
|
|
* @param message The error message
|
|
* @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) {
|
|
/**
|
|
* A location in the source code
|
|
*
|
|
* @param line The code of the line this is in
|
|
* @param column The column of this character, starting with 0
|
|
* @param row The row of this line, starting with 1
|
|
*/
|
|
public record Location(String line, int column, int row) {
|
|
public static Location create(String source, int index) {
|
|
if (index < 0) return new Location("", -1, -1);
|
|
int lineStart = source.lastIndexOf('\n', index);
|
|
int lineEnd = source.indexOf('\n', index);
|
|
if (lineEnd == -1) lineEnd = source.length();
|
|
|
|
int lineIndex = lineStart > 0 ? (int) source.substring(0, lineStart).chars().filter(c -> c == '\n').count() : 0;
|
|
int column = index - lineStart - 1;
|
|
|
|
String line = lineStart == source.length() - 1 ? "" : source.substring(lineStart + 1, lineEnd);
|
|
|
|
return new Location(line, column, lineIndex + 1);
|
|
}
|
|
|
|
@Override
|
|
public String toString() {
|
|
if (column >= line.length()) return "character " + (column + 1) + " of line " + row;
|
|
else return "'" + line.charAt(column) + "' (character " + (column + 1) + ")";
|
|
}
|
|
|
|
public String prettyPrint() {
|
|
String linePrefix = String.format("%1$6d", row) + " | ";
|
|
return linePrefix + line + "\n" + " ".repeat(linePrefix.length() + column) + "^-- ";
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 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 new LocationalError(message, Location.create(source, start), null);
|
|
}
|
|
|
|
/**
|
|
* 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) {
|
|
if (end == start) return create(source, start, message);
|
|
if (end < start) {
|
|
int a = end;
|
|
end = start;
|
|
start = a;
|
|
}
|
|
return new LocationalError(message, Location.create(source, start), Location.create(source, end));
|
|
}
|
|
|
|
/**
|
|
* Converts this error to a human-readable error message
|
|
*
|
|
* @return A string representation
|
|
*/
|
|
@Override
|
|
public String toString() {
|
|
if (start.column < 0) return "Error at unknown location: " + message;
|
|
if (end == null) return "Error at " + start + ": " + message + "\n" + start.prettyPrint() + "Here";
|
|
if (start.row == end.row) {
|
|
String linePrefix = String.format("%1$6d", start.row) + " | ";
|
|
return "Error at " + start + ": " + message + "\n"
|
|
+ linePrefix + start.line + "\n"
|
|
+ " ".repeat(linePrefix.length() + start.column) + "^"
|
|
+ "-".repeat(end.column - start.column - 1)
|
|
+ "^-- Here";
|
|
}
|
|
return "Error at " + start + ": " + message + "\n"
|
|
+ start.prettyPrint() + "From here"
|
|
+ end.prettyPrint() + "to here";
|
|
}
|
|
}
|