85 lines
2.4 KiB
JavaScript
85 lines
2.4 KiB
JavaScript
|
|
"use strict";
|
||
|
|
|
||
|
|
const GrammarError = require("../grammar-error");
|
||
|
|
|
||
|
|
class Defaults {
|
||
|
|
constructor(options) {
|
||
|
|
options = typeof options !== "undefined" ? options : {};
|
||
|
|
|
||
|
|
if (typeof options.error === "function") { this.error = options.error; }
|
||
|
|
if (typeof options.warning === "function") { this.warning = options.warning; }
|
||
|
|
if (typeof options.info === "function") { this.info = options.info; }
|
||
|
|
}
|
||
|
|
|
||
|
|
// eslint-disable-next-line class-methods-use-this -- Abstract
|
||
|
|
error() {
|
||
|
|
// Intentionally empty placeholder
|
||
|
|
}
|
||
|
|
|
||
|
|
// eslint-disable-next-line class-methods-use-this -- Abstract
|
||
|
|
warning() {
|
||
|
|
// Intentionally empty placeholder
|
||
|
|
}
|
||
|
|
|
||
|
|
// eslint-disable-next-line class-methods-use-this -- Abstract
|
||
|
|
info() {
|
||
|
|
// Intentionally empty placeholder
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
class Session {
|
||
|
|
constructor(options) {
|
||
|
|
this._callbacks = new Defaults(options);
|
||
|
|
this._firstError = null;
|
||
|
|
this.errors = 0;
|
||
|
|
/** @type {import("../peg").Problem[]} */
|
||
|
|
this.problems = [];
|
||
|
|
/** @type {import("../peg").Stage} */
|
||
|
|
this.stage = null;
|
||
|
|
}
|
||
|
|
|
||
|
|
error(...args) {
|
||
|
|
++this.errors;
|
||
|
|
// In order to preserve backward compatibility we cannot change `GrammarError`
|
||
|
|
// constructor, nor throw another class of error:
|
||
|
|
// - if we change `GrammarError` constructor, this will break plugins that
|
||
|
|
// throws `GrammarError`
|
||
|
|
// - if we throw another Error class, this will break parser clients that
|
||
|
|
// catches GrammarError
|
||
|
|
//
|
||
|
|
// So we use a compromise: we throw an `GrammarError` with all found problems
|
||
|
|
// in the `problems` property, but the thrown error itself is the first
|
||
|
|
// registered error.
|
||
|
|
//
|
||
|
|
// Thus when the old client catches the error it can find all properties on
|
||
|
|
// the Grammar error that it want. On the other hand the new client can
|
||
|
|
// inspect the `problems` property to get all problems.
|
||
|
|
if (this._firstError === null) {
|
||
|
|
this._firstError = new GrammarError(...args);
|
||
|
|
this._firstError.stage = this.stage;
|
||
|
|
this._firstError.problems = this.problems;
|
||
|
|
}
|
||
|
|
|
||
|
|
this.problems.push(["error", ...args]);
|
||
|
|
this._callbacks.error(this.stage, ...args);
|
||
|
|
}
|
||
|
|
|
||
|
|
warning(...args) {
|
||
|
|
this.problems.push(["warning", ...args]);
|
||
|
|
this._callbacks.warning(this.stage, ...args);
|
||
|
|
}
|
||
|
|
|
||
|
|
info(...args) {
|
||
|
|
this.problems.push(["info", ...args]);
|
||
|
|
this._callbacks.info(this.stage, ...args);
|
||
|
|
}
|
||
|
|
|
||
|
|
checkErrors() {
|
||
|
|
if (this.errors !== 0) {
|
||
|
|
throw this._firstError;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
module.exports = Session;
|