package com.github.charmoniumq.assembler.backend;
import java.util.List;
import org.antlr.v4.runtime.*;
public class ErrorMessages {
public static String recognitionException(RecognitionException e) {
Token offendingToken = e.getOffendingToken();
String bad = offendingToken.getText();
Parser parser = (Parser) e.getRecognizer();
// The following gets the 'hierarchy' of rules with the 0th element being the failed rule
List<String> stack = parser.getRuleInvocationStack(e.getCtx());
String brokenRule = stack.size() > 0 ? stack.get(0): "Unknown";
String message = "Unknown";
if (brokenRule.equals("source") || brokenRule.equals("codebyte") || brokenRule.equals("eof")) {
message = String.format("Unable to interpret \"%s\" as a command", bad);
} else if (brokenRule.equals("literal")) {
message = String.format("Invalid literal \"%s\". Must be binary, decimal, or hexidecimal", bad);
} else {
// unknown parser error
String next = e.getExpectedTokens().toString(e.getRecognizer().getVocabulary());
message = String.format("No error message for this yet\nContact the maintainer and present your source code, assembler version, and the following message:");
}
String errorLine = ((CommonTokenStream) e.getRecognizer().getInputStream())
.getTokenSource().getInputStream().toString().split("\n")[offendingToken.getLine() - 1];
return prettyFormat(message, brokenRule, offendingToken, errorLine);
}
public static String undefinedSymbol(PostProcessError e) {
ParserRuleContext ctx = e.getCtx();
Token offendingToken = ctx.getStart();
String message = e.getMessage();
String brokenRule = String.format(e.getRule());
// In this case, I don't really have the source code line that failed
// So put the token text that failed in the position it would be if it was in the source
StringBuilder partialLine = new StringBuilder();
for (int i = 0; i < offendingToken.getCharPositionInLine(); ++i) {
partialLine.append(".");
}
partialLine.append(offendingToken.getText());
return prettyFormat(message, brokenRule, ctx.getStart(), partialLine.toString());
}
private static String prettyFormat(String message, String brokenRule, Token offendingToken, String errorLine) {
int line = offendingToken.getLine();
int col = offendingToken.getCharPositionInLine();
String fileName = offendingToken.getInputStream().getSourceName();
int start = offendingToken.getStartIndex();
int stop = offendingToken.getStopIndex();
StringBuilder underline = new StringBuilder("");
for (int i = 0; i < col; i++) {
underline.append(" ");
}
if (start >= 0 && stop >= 0) {
for (int i = start; i <= stop; i++) {
underline.append("^");
}
}
String generalMessage = "Error: %s\nRule: %s\nFile: %s, Line: %d, Col: %d\nSource:\n%s\n%s\n";
return String.format(generalMessage, message, brokenRule, fileName, line, col, errorLine, underline);
}
}