WarpPI/core/src/main/java/it/cavallium/warppi/math/rules/dsl/errorutils/DslErrorMessageFormatter.java

125 lines
3.1 KiB
Java

package it.cavallium.warppi.math.rules.dsl.errorutils;
import it.cavallium.warppi.math.rules.dsl.DslError;
import it.cavallium.warppi.math.rules.dsl.UndefinedSubFunction;
import it.cavallium.warppi.math.rules.dsl.frontend.*;
import java.util.stream.Collectors;
/**
* Creates human-readable error messages from instances of {@link DslError}.
*/
public class DslErrorMessageFormatter implements DslError.Visitor<String> {
/**
* Formats the given <code>DslError</code> as a human-readable message, according to its type.
*
* @param error The error to format.
* @return One or more lines of text which describe the error (without a trailing newline).
*/
public String format(final DslError error) {
return error.accept(this);
}
@Override
public String visit(final IncompleteNumberLiteral incompleteNumberLiteral) {
return String.format(
"Number has a decimal point but no digits following it: %s",
incompleteNumberLiteral.getLiteral()
);
}
@Override
public String visit(final UndefinedSubFunction undefinedSubFunction) {
return String.format(
"Sub-function \"%s\" is used in a replacement pattern,\nbut not defined in the target pattern",
undefinedSubFunction.getName()
);
}
@Override
public String visit(final UnexpectedCharacters unexpectedCharacters) {
final String plural = unexpectedCharacters.getLength() > 1 ? "s" : "";
return String.format("Unexpected character%s: %s", plural, unexpectedCharacters.getUnexpectedCharacters());
}
@Override
public String visit(final UnexpectedToken unexpectedToken) {
final String suggestions;
if (unexpectedToken.getSuggested().isEmpty()) {
suggestions = "";
} else {
suggestions = "\nSome suggestions are: " + unexpectedToken.getSuggested().stream()
.map(DslErrorMessageFormatter::tokenTypeName)
.collect(Collectors.joining(", "));
}
return String.format(
"Unexpected %s%s",
tokenTypeName(unexpectedToken.getUnexpected().type),
suggestions
);
}
@Override
public String visit(final UnterminatedComment unterminatedComment) {
return "Unterminated comment";
}
private static String tokenTypeName(final TokenType type) {
switch (type) {
case EOF:
return "end of input";
case COLON:
return "\":\"";
case ARROW:
return "\"->\"";
case COMMA:
return "\",\"";
case LEFT_PAREN:
return "\"(\"";
case RIGHT_PAREN:
return "\")\"";
case LEFT_BRACKET:
return "\"[\"";
case RIGHT_BRACKET:
return "\"]\"";
case EQUALS:
return "\"=\"";
case PLUS:
return "\"+\"";
case MINUS:
return "\"-\"";
case PLUS_MINUS:
return "\"+-\"";
case TIMES:
return "\"*\"";
case DIVIDE:
return "\"/\"";
case POWER:
return "\"^\"";
case REDUCTION:
case EXPANSION:
case CALCULATION:
case EXISTENCE:
case ARCCOS:
case ARCSIN:
case ARCTAN:
case COS:
case SIN:
case TAN:
case ROOT:
case SQRT:
case LOG:
case UNDEFINED:
case PI:
case E:
return '"' + type.name().toLowerCase() + '"';
case NUMBER:
return "number";
case IDENTIFIER:
return "identifier";
}
throw new RuntimeException("unknown token type");
}
}