You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

220 lines
5.9 KiB
JavaScript

/*
* PEG.js runtime.
*
* Required by all parsers generated by PEG.js.
*/
PEG = {};
(function() {
/* ===== PEG.ArrayUtils ===== */
/* Array manipulation utility functions. */
PEG.ArrayUtils = {
map: function(array, callback) {
var result = [];
var length = array.length;
for (var i = 0; i < length; i++) {
result[i] = callback(array[i]);
}
return result;
}
};
/* ===== PEG.StringUtils ===== */
/* String manipulation utility functions. */
PEG.StringUtils = {
/*
* Surrounds the string with quotes and escapes characters inside so that the
* result is a valid JavaScript string.
*/
quote: function(s) {
/*
* ECMA-262, 5th ed., 7.8.4: All characters may appear literally in a string
* literal except for the closing quote character, backslash, carriage
* return, line separator, paragraph separator, and line feed. Any character
* may appear in the form of an escape sequence.
*/
return '"' + s
.replace(/\\/g, '\\\\') // backslash
.replace(/"/g, '\\"') // closing quote character
.replace(/\r/g, '\\r') // carriage return
.replace(/\u2028/g, '\\u2028') // line separator
.replace(/\u2029/g, '\\u2029') // paragraph separator
.replace(/\n/g, '\\n') // line feed
+ '"';
},
};
/* ===== PEG.Parser ===== */
/* Prototype of all parsers generated by PEG.js. */
PEG.Parser = function(startRule) { this._startRule = startRule; }
PEG.Parser.prototype = {
_matchFailed: function(failure) {
if (this._pos > this._rightmostMatchFailuresPos) {
this._rightmostMatchFailuresPos = this._pos;
this._rightmostMatchFailures = [];
}
this._rightmostMatchFailures.push(failure);
},
/*
* Parses the input with a generated parser. If the parsing is successfull,
* returns a value explicitly or implicitly specified by the grammar from
* which the parser was generated (see |PEG.buildParser|). If the parsing is
* unsuccessful, throws |PEG.Parser.SyntaxError| describing the error.
*/
parse: function(input) {
var that = this;
function initialize() {
that._input = input;
that._pos = 0;
that._rightmostMatchFailuresPos = 0;
that._rightmostMatchFailures = [];
that._cache = {};
}
function buildErrorMessage() {
function buildExpectedFromMatchFailures(failures) {
switch (failures.length) {
case 0:
return "nothing";
case 1:
return failures[0].toString();
default:
return PEG.ArrayUtils.map(
failures.slice(0, failures.length - 1),
function(failure) { return failure.toString(); }
).join(", ")
+ " or "
+ failures[failures.length - 1].toString();
}
}
if (that._pos === 0) {
var expected = buildExpectedFromMatchFailures(
that._rightmostMatchFailures
);
var actual = that._rightmostMatchFailuresPos < that._input.length
? PEG.StringUtils.quote(
that._input.charAt(that._rightmostMatchFailuresPos)
)
: "end of input";
} else {
var expected = "end of input";
var actual = PEG.StringUtils.quote(that._input.charAt(that._pos));
}
return "Expected " + expected + " but " + actual + " found.";
}
function computeErrorPosition() {
/*
* The first idea was to use |String.split| to break the input up to the
* error position along newlines and derive the line and column from
* there. However IE's |split| implementation is so broken that it was
* enough to prevent it.
*/
var input = that._input;
var pos = that._rightmostMatchFailuresPos;
var line = 1;
var column = 1;
var seenCR = false;
for (var i = 0; i < pos; i++) {
var ch = input.charAt(i);
if (ch === "\n") {
if (!seenCR) { line++; }
column = 1;
seenCR = false;
} else if (ch === "\r" | ch === "\u2028" || ch === "\u2029") {
line++;
column = 1;
seenCR = true;
} else {
column++;
seenCR = false;
}
}
return { line: line, column: column };
}
initialize();
var initialContext = {
reportMatchFailures: true,
};
var result = this["_parse_" + this._startRule](initialContext);
if (result === null || this._pos !== input.length) {
var errorPosition = computeErrorPosition();
throw new PEG.Parser.SyntaxError(
errorPosition.line,
errorPosition.column,
buildErrorMessage()
);
}
return result;
},
/* Returns the parser source code. */
toSource: function() { return this._source; }
};
/* ===== PEG.Parser.LiteralMatchFailure ===== */
/* Stores information about a literal match failure. */
PEG.Parser.LiteralMatchFailure = function(value) { this._value = value; };
PEG.Parser.LiteralMatchFailure.prototype = {
toString: function() { return PEG.StringUtils.quote(this._value); }
};
/* ===== PEG.Parser.AnyMatchFailure ===== */
/* Stores information about a failure to match a "." expression. */
PEG.Parser.AnyMatchFailure = function() {}
PEG.Parser.AnyMatchFailure.prototype = {
toString: function() { return "any character"; }
};
/* ===== PEG.Parser.NamedRuleMatchFailure ===== */
/* Stores information about a failure to match a named rule. */
PEG.Parser.NamedRuleMatchFailure = function(humanName) { this._humanName = humanName; }
PEG.Parser.NamedRuleMatchFailure.prototype = {
toString: function() { return this._humanName; }
};
/* ===== PEG.Parser.SyntaxError ===== */
/* Thrown when a parser encounters a syntax error. */
PEG.Parser.SyntaxError = function(line, column, message) {
this.name = "PEG.Parser.SyntaxError";
this.line = line;
this.column = column;
this.message = message;
};
PEG.Parser.SyntaxError.prototype = Error.prototype;
})();