UNPKG

antlr-ng

Version:

Next generation ANTLR Tool

278 lines (277 loc) 8.55 kB
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 };