antlr-ng
Version:
Next generation ANTLR Tool
278 lines (277 loc) • 8.55 kB
JavaScript
var __defProp = Object.defineProperty;
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
import { ErrorBuffer, STGroupString } from "stringtemplate4ts";
import { basename } from "path";
import { ANTLRMessage } from "./ANTLRMessage.js";
import { IssueCode, IssueSeverity, severityMap } from "./Issues.js";
import { ToolListener } from "./ToolListener.js";
const messageFormats = /* @__PURE__ */ new Map([
["antlr", `
location(file, line, column) ::= "<file>:<line>:<column>:"
message(id, text) ::= "(<id>) <text>"
report(location, message, type) ::= "<type>(<message.id>): <location> <message.text>"
wantsSingleLineMessage() ::= "false"
`],
["gnu", `
location(file, line, column) ::= "<file>:<line>:<column>:"
message(id, text) ::= "<text> [error <id>]"
report(location, message, type) ::= "<location> <type>: <message>"
wantsSingleLineMessage() ::= "true"
`],
["vs2005", `
location(file, line, column) ::= "<file>(<line>,<column>)"
message(id, text) ::= "error <id> : <text>"
report(location, message, type) ::= "<location> : <type> <message.id> : <message.text>"
wantsSingleLineMessage() ::= "true"
`]
]);
class ErrorManager {
constructor(msgFormat, longMessages, warningsAreErrors) {
this.longMessages = longMessages;
this.warningsAreErrors = warningsAreErrors;
this.errors = 0;
this.warnings = 0;
this.loadFormat(msgFormat ?? "antlr");
}
static {
__name(this, "ErrorManager");
}
static loadedFormats = /* @__PURE__ */ new Map();
errors;
warnings;
/** All errors that have been generated */
errorTypes = /* @__PURE__ */ new Set();
/** The group of templates that represent the current message format. */
format;
formatName;
initSTListener = new ErrorBuffer();
listeners = new Array();
/**
* Track separately so if someone adds a listener, it's the only one instead of it and the default stderr listener.
*/
defaultListener = new ToolListener(this);
static fatalInternalError(error, e) {
ErrorManager.internalError(error, e);
throw new Error(error, { cause: e });
}
static internalError(error, e) {
if (e) {
const location = ErrorManager.getLastNonErrorManagerCodeLocation(e);
ErrorManager.internalError(`Exception ${e}@${location}: ${error}`);
} else {
const location = ErrorManager.getLastNonErrorManagerCodeLocation(new Error());
const msg = location + ": " + error;
console.error("internal error: " + msg);
}
}
/** @returns The first non ErrorManager code location for generating messages. */
static getLastNonErrorManagerCodeLocation(e) {
const stack = e.stack.split("\n");
let entry = "";
for (entry of stack) {
if (!entry.includes("ErrorManager")) {
break;
}
}
return entry;
}
formatWantsSingleLineMessage() {
const result = this.format.getInstanceOf("wantsSingleLineMessage")?.render();
return result === "true" ? true : false;
}
getMessageTemplate(msg) {
const longMessages = this.longMessages;
const messageST = msg.getMessageTemplate(longMessages ?? false);
const locationST = this.getLocationFormat();
const reportST = this.getReportFormat(msg.issue.severity);
const messageFormatST = this.getMessageFormat();
let locationValid = false;
if (msg.line !== -1) {
locationST.add("line", msg.line);
locationValid = true;
}
if (msg.column !== -1) {
locationST.add("column", msg.column);
locationValid = true;
}
if (msg.fileName) {
let displayFileName = msg.fileName;
if (this.formatName === "antlr") {
displayFileName = basename(msg.fileName);
} else {
}
locationST.add("file", displayFileName);
locationValid = true;
}
messageFormatST.add("id", msg.issueCode);
messageFormatST.add("text", messageST);
if (locationValid) {
reportST?.add("location", locationST);
}
reportST?.add("message", messageFormatST);
return reportST;
}
toolError(...allArgs) {
let msg;
if (allArgs.length < 1) {
throw new Error("Invalid number of arguments");
}
const issueType = allArgs.shift();
if (allArgs.length > 0) {
const error = allArgs[0];
if (error instanceof Error) {
allArgs.shift();
msg = new ANTLRMessage(issueType, "", error, -1, -1, ...allArgs);
} else {
msg = new ANTLRMessage(issueType, "", -1, -1, ...allArgs);
}
} else {
msg = new ANTLRMessage(issueType, "", -1, -1);
}
this.emit(msg);
}
grammarError(errorType, fileName, position, ...args) {
const msg = new ANTLRMessage(
errorType,
fileName,
position?.line ?? -1,
position?.column ?? -1,
...args
);
this.emit(msg);
}
addListener(tl) {
this.listeners.push(tl);
}
removeListener(tl) {
const index = this.listeners.indexOf(tl);
if (index >= 0) {
this.listeners.splice(index, 1);
}
}
removeListeners() {
this.listeners = [];
}
syntaxError(errorType, fileName, line, column, antlrException, ...args) {
const msg = new ANTLRMessage(errorType, fileName, antlrException, line, column, ...args);
this.emit(msg);
}
info(msg) {
if (this.listeners.length === 0) {
this.defaultListener.info(msg);
return;
}
for (const l of this.listeners) {
l.info(msg);
}
}
error(msg) {
++this.errors;
if (this.listeners.length === 0) {
this.defaultListener.error(msg);
return;
}
for (const l of this.listeners) {
l.error(msg);
}
}
warning(msg) {
if (this.listeners.length === 0) {
this.defaultListener.warning(msg);
} else {
for (const l of this.listeners) {
l.warning(msg);
}
}
if (this.warningsAreErrors) {
this.emit(new ANTLRMessage(IssueCode.WarningTreatedAsErrors, msg.fileName, msg.line, msg.column));
}
}
emit(msg) {
switch (msg.issue.severity) {
case IssueSeverity.WarningOneOff: {
if (this.errorTypes.has(msg.issueCode)) {
break;
}
}
case IssueSeverity.Warning: {
this.warnings++;
this.warning(msg);
break;
}
case IssueSeverity.ErrorOneOff: {
if (this.errorTypes.has(msg.issueCode)) {
break;
}
}
case IssueSeverity.Error:
case IssueSeverity.Fatal: {
this.error(msg);
break;
}
default:
}
this.errorTypes.add(msg.issueCode);
}
/**
* Return a StringTemplate that refers to the current format used for emitting messages.
*/
getLocationFormat() {
return this.format.getInstanceOf("location");
}
getReportFormat(severity) {
const st = this.format.getInstanceOf("report");
st?.add("type", severityMap.get(severity));
return st;
}
getMessageFormat() {
return this.format.getInstanceOf("message");
}
/**
* The format gets reset either from the Tool if the user supplied a command line option to that effect.
* Otherwise we just use the default "antlr".
*/
loadFormat(formatName) {
let loadedFormat = ErrorManager.loadedFormats.get(formatName);
if (!loadedFormat) {
let templates = messageFormats.get(formatName);
if (!templates) {
templates = messageFormats.get("antlr");
if (!templates) {
throw new Error("Unknown message format: " + formatName);
}
}
loadedFormat = new STGroupString("ErrorManager", templates, "<", ">");
ErrorManager.loadedFormats.set(formatName, loadedFormat);
}
this.formatName = formatName;
this.format = loadedFormat;
if (this.initSTListener.size > 0) {
throw new Error("Can't load messages format file:\n" + this.initSTListener.toString());
}
const formatOK = this.verifyFormat();
if (!formatOK) {
throw new Error("ANTLR messages format " + formatName + " invalid");
}
}
/** Verify the message format template group */
verifyFormat() {
let ok = true;
if (!this.format.isDefined("location")) {
console.error("Format template 'location' not found in " + this.formatName);
ok = false;
}
if (!this.format.isDefined("message")) {
console.error("Format template 'message' not found in " + this.formatName);
ok = false;
}
if (!this.format.isDefined("report")) {
console.error("Format template 'report' not found in " + this.formatName);
ok = false;
}
return ok;
}
}
export {
ErrorManager
};