[muscript] Generate error data in create method, not in toString

This commit is contained in:
Johannes Frohnmeyer 2022-06-13 11:06:01 +02:00
parent ed680f57a9
commit a9cd45c39d
Signed by: Johannes
GPG Key ID: E76429612C2929F4
3 changed files with 34 additions and 19 deletions

View File

@ -3,29 +3,44 @@ package io.gitlab.jfronny.muscript.compiler;
/** /**
* Class for storing errors produced while parsing. * Class for storing errors produced while parsing.
*/ */
public record Error(String source, int character, String message) { public record Error(String message, String line, int lineNumber, int column) {
@Override /**
public String toString() { * Generates an error by getting the relevant data from what is available while lexing/parsing
StringBuilder builder = new StringBuilder(); * @param source The complete source for the code that generated this error
if (character >= source.length()) { * @param character The index of the current character
builder.append("Error at character ").append(character); * @param message The error message
} * @return An error using the provided information
else { */
builder.append("Error at '").append(source.charAt(character)).append("' (character ").append(character).append(")"); public static Error create(String source, int character, String message) {
}
builder.append(": ").append(message);
int lineStart = source.lastIndexOf('\n', character); int lineStart = source.lastIndexOf('\n', character);
int lineEnd = source.indexOf('\n', character); int lineEnd = source.indexOf('\n', character);
if (lineEnd == -1) lineEnd = source.length(); if (lineEnd == -1) lineEnd = source.length();
String line = source.substring(lineStart + 1, lineEnd); int lineIndex = lineStart > 0 ? (int) source.substring(0, lineStart).chars().filter(c -> c == '\n').count() : 0;
int lineNumber = lineStart > 0 ? (int) source.substring(0, lineStart).chars().filter(c -> c == '\n').count() : 1; int column = character - lineStart;
return new Error(message, source.substring(lineStart + 1, lineEnd), lineIndex + 1, column);
}
/**
* Converts this error to a human-readable error message
* @return A string representation
*/
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
if (column > line.length())
builder.append("Error at character ").append(column);
else
builder.append("Error at '").append(line.charAt(column - 1)).append("' (character ").append(column).append(")");
builder.append(": ").append(message);
String linePrefix = String.format("%1$6d", lineNumber) + " | "; String linePrefix = String.format("%1$6d", lineNumber) + " | ";
builder.append('\n').append(linePrefix).append(line); builder.append('\n').append(linePrefix).append(line);
builder.append('\n').append(" ".repeat(linePrefix.length() + (character - lineStart - 1))).append("^-- Here"); builder.append('\n').append(" ".repeat(linePrefix.length() + (column - 1))).append("^-- Here");
return builder.toString(); return builder.toString();
} }
} }

View File

@ -230,7 +230,7 @@ public class Parser {
// Helpers // Helpers
private ParseException error(String message) { private ParseException error(String message) {
return new ParseException(new Error(lexer.source, current.current - 1, message)); return new ParseException(Error.create(lexer.source, current.current - 1, message));
} }
private TokenData consume(Token token, String message) { private TokenData consume(Token token, String message) {

View File

@ -9,17 +9,17 @@ public class ErrorTest {
@Test @Test
void invalidCode() { void invalidCode() {
assertEquals(""" assertEquals("""
Error at 'e' (character 8): Expected number but is Boolean Error at 'e' (character 9): Expected number but is Boolean
1 | 15 + true 1 | 15 + true
^-- Here""", ^-- Here""",
assertThrows(Parser.ParseException.class, () -> Parser.parse("15 + true")).error.toString()); assertThrows(Parser.ParseException.class, () -> Parser.parse("15 + true")).error.toString());
assertEquals(""" assertEquals("""
Error at ''' (character 9): Expected number but is String Error at ''' (character 10): Expected number but is String
1 | 15 + 'yes' 1 | 15 + 'yes'
^-- Here""", ^-- Here""",
assertThrows(Parser.ParseException.class, () -> Parser.parse("15 + 'yes'")).error.toString()); assertThrows(Parser.ParseException.class, () -> Parser.parse("15 + 'yes'")).error.toString());
assertEquals(""" assertEquals("""
Error at '=' (character 7): Unexpected character Error at '=' (character 8): Unexpected character
1 | string = 'Value' 1 | string = 'Value'
^-- Here""", ^-- Here""",
assertThrows(Parser.ParseException.class, () -> Parser.parse("string = 'Value'")).error.toString()); assertThrows(Parser.ParseException.class, () -> Parser.parse("string = 'Value'")).error.toString());