|
|
|
/*
|
|
|
|
* PEG.js runtime.
|
|
|
|
*
|
|
|
|
* Required by all parsers generated by PEG.js.
|
|
|
|
*/
|
|
|
|
|
|
|
|
PEG = {};
|
|
|
|
|
|
|
|
(function() {
|
|
|
|
|
|
|
|
/* ===== PEG.ArrayUtils ===== */
|
|
|
|
|
|
|
|
/* Array manipulation utility functions. */
|
|
|
|
|
|
|
|
PEG.ArrayUtils = {
|
|
|
|
each: function(array, callback) {
|
|
|
|
var length = array.length;
|
|
|
|
for (var i = 0; i < length; i++) {
|
|
|
|
callback(array[i]);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
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.RegExpUtils ===== */
|
|
|
|
|
|
|
|
/* RegExp manipulation utility functions. */
|
|
|
|
|
|
|
|
PEG.RegExpUtils = {
|
|
|
|
/*
|
|
|
|
* Escapes characters inside the string so that it can be used as a list of
|
|
|
|
* characters in a character class of a regular expresion.
|
|
|
|
*/
|
|
|
|
quoteForClass: function(s) {
|
|
|
|
/* Based on ECMA-262, 5th ed., 7.8.5 & 15.10.1. */
|
|
|
|
return s
|
|
|
|
.replace(/\\/g, '\\\\') // backslash
|
|
|
|
.replace(/\//g, '\\/') // closing slash
|
|
|
|
.replace(/]/g, '\\]') // closing bracket
|
|
|
|
.replace(/-/g, '\\-') // dash
|
|
|
|
.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 "end of input";
|
|
|
|
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();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
var expected = buildExpectedFromMatchFailures(
|
|
|
|
that._rightmostMatchFailures
|
|
|
|
);
|
|
|
|
var pos = Math.max(that._pos, that._rightmostMatchFailuresPos);
|
|
|
|
var actual = pos < that._input.length
|
|
|
|
? PEG.StringUtils.quote(that._input.charAt(pos))
|
|
|
|
: "end of input";
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The parser is now in one of the following three states:
|
|
|
|
*
|
|
|
|
* 1. The parser successfully parsed the whole input.
|
|
|
|
*
|
|
|
|
* - |result !== null|
|
|
|
|
* - |that._pos === input.length|
|
|
|
|
* - |that._rightmostMatchFailures.length| may or may not contain
|
|
|
|
* something
|
|
|
|
*
|
|
|
|
* 2. The parser successfully parsed only a part of the input.
|
|
|
|
*
|
|
|
|
* - |result !== null|
|
|
|
|
* - |that._pos < input.length|
|
|
|
|
* - |that._rightmostMatchFailures.length| may or may not contain
|
|
|
|
* something
|
|
|
|
*
|
|
|
|
* 3. The parser did not successfully parse any part of the input.
|
|
|
|
*
|
|
|
|
* - |result === null|
|
|
|
|
* - |that._pos === 0|
|
|
|
|
* - |that._rightmostMatchFailures.length| contains at least one failure
|
|
|
|
*
|
|
|
|
* All code following this comment (including called functions) must
|
|
|
|
* handle these states.
|
|
|
|
*/
|
|
|
|
if (result === null || this._pos !== input.length) {
|
|
|
|
var errorPosition = computeErrorPosition();
|
|
|
|
throw new PEG.Parser.SyntaxError(
|
|
|
|
buildErrorMessage(),
|
|
|
|
errorPosition.line,
|
|
|
|
errorPosition.column
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
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.ClassMatchFailure ===== */
|
|
|
|
|
|
|
|
/* Stores information about a class match failure. */
|
|
|
|
|
|
|
|
PEG.Parser.ClassMatchFailure = function(characters) {
|
|
|
|
this._characters = characters;
|
|
|
|
};
|
|
|
|
|
|
|
|
PEG.Parser.ClassMatchFailure.prototype = {
|
|
|
|
toString: function() { return "[" + this._characters + "]"; }
|
|
|
|
};
|
|
|
|
|
|
|
|
/* ===== 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(displayName) {
|
|
|
|
this._displayName = displayName;
|
|
|
|
}
|
|
|
|
|
|
|
|
PEG.Parser.NamedRuleMatchFailure.prototype = {
|
|
|
|
toString: function() { return this._displayName; }
|
|
|
|
};
|
|
|
|
|
|
|
|
/* ===== PEG.Parser.SyntaxError ===== */
|
|
|
|
|
|
|
|
/* Thrown when a parser encounters a syntax error. */
|
|
|
|
|
|
|
|
PEG.Parser.SyntaxError = function(message, line, column) {
|
|
|
|
this.name = "PEG.Parser.SyntaxError";
|
|
|
|
this.message = message;
|
|
|
|
this.line = line;
|
|
|
|
this.column = column;
|
|
|
|
};
|
|
|
|
|
|
|
|
PEG.Parser.SyntaxError.prototype = Error.prototype;
|
|
|
|
|
|
|
|
})();
|