package org.antlr.v4.tool;
import org.antlr.v4.Tool;
import org.stringtemplate.v4.ST;
import org.stringtemplate.v4.STGroup;
import org.stringtemplate.v4.STGroupFile;
import org.stringtemplate.v4.misc.ErrorBuffer;
import java.io.File;
import java.net.URL;
import java.util.Collection;
import java.util.EnumSet;
import java.util.Set;
public class ErrorManager {
public static final String FORMATS_DIR = "org/antlr/v4/tool/templates/messages/formats/";
public Tool tool;
public int errors;
public int warnings;
public Set<ErrorType> errorTypes = EnumSet.noneOf(ErrorType.class);
STGroup format;
String formatName;
ErrorBuffer initSTListener = new ErrorBuffer();
public ErrorManager(Tool tool) {
this.tool = tool;
}
public void resetErrorState() {
errors = 0;
warnings = 0;
}
public ST getMessageTemplate(ANTLRMessage msg) {
ST messageST = msg.getMessageTemplate(tool.longMessages);
ST locationST = getLocationFormat();
ST reportST = getReportFormat(msg.getErrorType().severity);
ST messageFormatST = getMessageFormat();
boolean locationValid = false;
if (msg.line != -1) {
locationST.add("line", msg.line);
locationValid = true;
}
if (msg.charPosition != -1) {
locationST.add("column", msg.charPosition);
locationValid = true;
}
if (msg.fileName != null) {
String displayFileName = msg.fileName;
if (format.equals("antlr")) {
File f = new File(msg.fileName);
if ( f.exists() ) {
displayFileName = f.getName();
}
}
else {
}
locationST.add("file", displayFileName);
locationValid = true;
}
messageFormatST.add("id", msg.getErrorType().code);
messageFormatST.add("text", messageST);
if (locationValid) reportST.add("location", locationST);
reportST.add("message", messageFormatST);
return reportST;
}
public ST getLocationFormat() {
return format.getInstanceOf("location");
}
public ST getReportFormat(ErrorSeverity severity) {
ST st = format.getInstanceOf("report");
st.add("type", severity.getText());
return st;
}
public ST getMessageFormat() {
return format.getInstanceOf("message");
}
public boolean formatWantsSingleLineMessage() {
return format.getInstanceOf("wantsSingleLineMessage").render().equals("true");
}
public void info(String msg) { tool.info(msg); }
public void syntaxError(ErrorType etype,
String fileName,
org.antlr.runtime.Token token,
org.antlr.runtime.RecognitionException antlrException,
Object... args)
{
ANTLRMessage msg = new GrammarSyntaxMessage(etype,fileName,token,antlrException,args);
emit(etype, msg);
}
public static void fatalInternalError(String error, Throwable e) {
internalError(error, e);
throw new RuntimeException(error, e);
}
public static void internalError(String error, Throwable e) {
StackTraceElement location = getLastNonErrorManagerCodeLocation(e);
internalError("Exception "+e+"@"+location+": "+error);
}
public static void internalError(String error) {
StackTraceElement location =
getLastNonErrorManagerCodeLocation(new Exception());
String msg = location+": "+error;
System.err.println("internal error: "+msg);
}
public void toolError(ErrorType errorType, Object... args) {
toolError(errorType, null, args);
}
public void toolError(ErrorType errorType, Throwable e, Object... args) {
ToolMessage msg = new ToolMessage(errorType, e, args);
emit(errorType, msg);
}
public void grammarError(ErrorType etype,
String fileName,
org.antlr.runtime.Token token,
Object... args)
{
ANTLRMessage msg = new GrammarSemanticsMessage(etype,fileName,token,args);
emit(etype, msg);
}
public void leftRecursionCycles(String fileName, Collection<? extends Collection<Rule>> cycles) {
errors++;
ANTLRMessage msg = new LeftRecursionCyclesMessage(fileName, cycles);
tool.error(msg);
}
public int getNumErrors() {
return errors;
}
private static StackTraceElement getLastNonErrorManagerCodeLocation(Throwable e) {
StackTraceElement[] stack = e.getStackTrace();
int i = 0;
for (; i < stack.length; i++) {
StackTraceElement t = stack[i];
if (!t.toString().contains("ErrorManager")) {
break;
}
}
StackTraceElement location = stack[i];
return location;
}
@SuppressWarnings("fallthrough")
public void emit(ErrorType etype, ANTLRMessage msg) {
switch ( etype.severity ) {
case WARNING_ONE_OFF:
if ( errorTypes.contains(etype) ) break;
case WARNING:
warnings++;
tool.warning(msg);
break;
case ERROR_ONE_OFF:
if ( errorTypes.contains(etype) ) break;
case ERROR:
errors++;
tool.error(msg);
break;
}
errorTypes.add(etype);
}
public void setFormat(String formatName) {
this.formatName = formatName;
String fileName = FORMATS_DIR +formatName+STGroup.GROUP_FILE_EXTENSION;
ClassLoader cl = Thread.currentThread().getContextClassLoader();
URL url = cl.getResource(fileName);
if ( url==null ) {
cl = ErrorManager.class.getClassLoader();
url = cl.getResource(fileName);
}
if ( url==null && formatName.equals("antlr") ) {
rawError("ANTLR installation corrupted; cannot find ANTLR messages format file "+fileName);
panic();
}
else if ( url==null ) {
rawError("no such message format file "+fileName+" retrying with default ANTLR format");
setFormat("antlr");
return;
}
format = new STGroupFile(url, "UTF-8", '<', '>');
format.load();
if ( !initSTListener.errors.isEmpty() ) {
rawError("ANTLR installation corrupted; can't load messages format file:\n"+
initSTListener.toString());
panic();
}
boolean formatOK = verifyFormat();
if ( !formatOK && formatName.equals("antlr") ) {
rawError("ANTLR installation corrupted; ANTLR messages format file "+formatName+".stg incomplete");
panic();
}
else if ( !formatOK ) {
setFormat("antlr");
}
}
protected boolean verifyFormat() {
boolean ok = true;
if (!format.isDefined("location")) {
System.err.println("Format template 'location' not found in " + formatName);
ok = false;
}
if (!format.isDefined("message")) {
System.err.println("Format template 'message' not found in " + formatName);
ok = false;
}
if (!format.isDefined("report")) {
System.err.println("Format template 'report' not found in " + formatName);
ok = false;
}
return ok;
}
static void rawError(String msg) {
System.err.println(msg);
}
static void rawError(String msg, Throwable e) {
rawError(msg);
e.printStackTrace(System.err);
}
public void panic(ErrorType errorType, Object... args) {
ToolMessage msg = new ToolMessage(errorType, args);
ST msgST = getMessageTemplate(msg);
String outputMsg = msgST.render();
if ( formatWantsSingleLineMessage() ) {
outputMsg = outputMsg.replace('\n', ' ');
}
panic(outputMsg);
}
public static void panic(String msg) {
rawError(msg);
panic();
}
public static void panic() {
throw new Error("ANTLR ErrorManager panic");
}
}