mirror of
https://github.com/pulsar-edit/pulsar.git
synced 2024-11-14 15:20:28 +03:00
4529 lines
131 KiB
JavaScript
4529 lines
131 KiB
JavaScript
/*
|
|
* PEG.js 0.7.0
|
|
*
|
|
* http://pegjs.majda.cz/
|
|
*
|
|
* Copyright (c) 2010-2012 David Majda
|
|
* Licensend under the MIT license.
|
|
*/
|
|
var PEG = (function(undefined) {
|
|
|
|
var PEG = {
|
|
/* PEG.js version (uses semantic versioning). */
|
|
VERSION: "0.7.0",
|
|
|
|
/*
|
|
* Generates a parser from a specified grammar and returns it.
|
|
*
|
|
* The grammar must be a string in the format described by the metagramar in
|
|
* the parser.pegjs file.
|
|
*
|
|
* Throws |PEG.parser.SyntaxError| if the grammar contains a syntax error or
|
|
* |PEG.GrammarError| if it contains a semantic error. Note that not all
|
|
* errors are detected during the generation and some may protrude to the
|
|
* generated parser and cause its malfunction.
|
|
*/
|
|
buildParser: function(grammar, options) {
|
|
return PEG.compiler.compile(PEG.parser.parse(grammar), options);
|
|
}
|
|
};
|
|
|
|
/* Thrown when the grammar contains an error. */
|
|
|
|
PEG.GrammarError = function(message) {
|
|
this.name = "PEG.GrammarError";
|
|
this.message = message;
|
|
};
|
|
|
|
PEG.GrammarError.prototype = Error.prototype;
|
|
|
|
/* Like Python's |range|, but without |step|. */
|
|
function range(start, stop) {
|
|
if (stop === undefined) {
|
|
stop = start;
|
|
start = 0;
|
|
}
|
|
|
|
var result = new Array(Math.max(0, stop - start));
|
|
for (var i = 0, j = start; j < stop; i++, j++) {
|
|
result[i] = j;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
function find(array, callback) {
|
|
var length = array.length;
|
|
for (var i = 0; i < length; i++) {
|
|
if (callback(array[i])) {
|
|
return array[i];
|
|
}
|
|
}
|
|
}
|
|
|
|
function contains(array, value) {
|
|
/*
|
|
* Stupid IE does not have Array.prototype.indexOf, otherwise this function
|
|
* would be a one-liner.
|
|
*/
|
|
var length = array.length;
|
|
for (var i = 0; i < length; i++) {
|
|
if (array[i] === value) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
function each(array, callback) {
|
|
var length = array.length;
|
|
for (var i = 0; i < length; i++) {
|
|
callback(array[i], i);
|
|
}
|
|
}
|
|
|
|
function map(array, callback) {
|
|
var result = [];
|
|
var length = array.length;
|
|
for (var i = 0; i < length; i++) {
|
|
result[i] = callback(array[i], i);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
function pluck(array, key) {
|
|
return map(array, function (e) { return e[key]; });
|
|
}
|
|
|
|
function keys(object) {
|
|
var result = [];
|
|
for (var key in object) {
|
|
result.push(key);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
function values(object) {
|
|
var result = [];
|
|
for (var key in object) {
|
|
result.push(object[key]);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/*
|
|
* Returns a string padded on the left to a desired length with a character.
|
|
*
|
|
* The code needs to be in sync with the code template in the compilation
|
|
* function for "action" nodes.
|
|
*/
|
|
function padLeft(input, padding, length) {
|
|
var result = input;
|
|
|
|
var padLength = length - input.length;
|
|
for (var i = 0; i < padLength; i++) {
|
|
result = padding + result;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
/*
|
|
* Returns an escape sequence for given character. Uses \x for characters <=
|
|
* 0xFF to save space, \u for the rest.
|
|
*
|
|
* The code needs to be in sync with the code template in the compilation
|
|
* function for "action" nodes.
|
|
*/
|
|
function escape(ch) {
|
|
var charCode = ch.charCodeAt(0);
|
|
var escapeChar;
|
|
var length;
|
|
|
|
if (charCode <= 0xFF) {
|
|
escapeChar = 'x';
|
|
length = 2;
|
|
} else {
|
|
escapeChar = 'u';
|
|
length = 4;
|
|
}
|
|
|
|
return '\\' + escapeChar + padLeft(charCode.toString(16).toUpperCase(), '0', length);
|
|
}
|
|
|
|
/*
|
|
* Surrounds the string with quotes and escapes characters inside so that the
|
|
* result is a valid JavaScript string.
|
|
*
|
|
* The code needs to be in sync with the code template in the compilation
|
|
* function for "action" nodes.
|
|
*/
|
|
function quote(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.
|
|
*
|
|
* For portability, we also escape escape all control and non-ASCII
|
|
* characters. Note that "\0" and "\v" escape sequences are not used because
|
|
* JSHint does not like the first and IE the second.
|
|
*/
|
|
return '"' + s
|
|
.replace(/\\/g, '\\\\') // backslash
|
|
.replace(/"/g, '\\"') // closing quote character
|
|
.replace(/\x08/g, '\\b') // backspace
|
|
.replace(/\t/g, '\\t') // horizontal tab
|
|
.replace(/\n/g, '\\n') // line feed
|
|
.replace(/\f/g, '\\f') // form feed
|
|
.replace(/\r/g, '\\r') // carriage return
|
|
.replace(/[\x00-\x07\x0B\x0E-\x1F\x80-\uFFFF]/g, escape)
|
|
+ '"';
|
|
}
|
|
|
|
/*
|
|
* Escapes characters inside the string so that it can be used as a list of
|
|
* characters in a character class of a regular expression.
|
|
*/
|
|
function quoteForRegexpClass(s) {
|
|
/*
|
|
* Based on ECMA-262, 5th ed., 7.8.5 & 15.10.1.
|
|
*
|
|
* For portability, we also escape escape all control and non-ASCII
|
|
* characters.
|
|
*/
|
|
return s
|
|
.replace(/\\/g, '\\\\') // backslash
|
|
.replace(/\//g, '\\/') // closing slash
|
|
.replace(/\]/g, '\\]') // closing bracket
|
|
.replace(/-/g, '\\-') // dash
|
|
.replace(/\0/g, '\\0') // null
|
|
.replace(/\t/g, '\\t') // horizontal tab
|
|
.replace(/\n/g, '\\n') // line feed
|
|
.replace(/\v/g, '\\x0B') // vertical tab
|
|
.replace(/\f/g, '\\f') // form feed
|
|
.replace(/\r/g, '\\r') // carriage return
|
|
.replace(/[\x01-\x08\x0E-\x1F\x80-\uFFFF]/g, escape);
|
|
}
|
|
|
|
/*
|
|
* Builds a node visitor -- a function which takes a node and any number of
|
|
* other parameters, calls an appropriate function according to the node type,
|
|
* passes it all its parameters and returns its value. The functions for various
|
|
* node types are passed in a parameter to |buildNodeVisitor| as a hash.
|
|
*/
|
|
function buildNodeVisitor(functions) {
|
|
return function(node) {
|
|
return functions[node.type].apply(null, arguments);
|
|
};
|
|
}
|
|
|
|
function findRuleByName(ast, name) {
|
|
return find(ast.rules, function(r) { return r.name === name; });
|
|
}
|
|
PEG.parser = (function(){
|
|
/*
|
|
* Generated by PEG.js 0.7.0.
|
|
*
|
|
* http://pegjs.majda.cz/
|
|
*/
|
|
|
|
function quote(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.
|
|
*
|
|
* For portability, we also escape escape all control and non-ASCII
|
|
* characters. Note that "\0" and "\v" escape sequences are not used
|
|
* because JSHint does not like the first and IE the second.
|
|
*/
|
|
return '"' + s
|
|
.replace(/\\/g, '\\\\') // backslash
|
|
.replace(/"/g, '\\"') // closing quote character
|
|
.replace(/\x08/g, '\\b') // backspace
|
|
.replace(/\t/g, '\\t') // horizontal tab
|
|
.replace(/\n/g, '\\n') // line feed
|
|
.replace(/\f/g, '\\f') // form feed
|
|
.replace(/\r/g, '\\r') // carriage return
|
|
.replace(/[\x00-\x07\x0B\x0E-\x1F\x80-\uFFFF]/g, escape)
|
|
+ '"';
|
|
}
|
|
|
|
var result = {
|
|
/*
|
|
* 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, startRule) {
|
|
var parseFunctions = {
|
|
"grammar": parse_grammar,
|
|
"initializer": parse_initializer,
|
|
"rule": parse_rule,
|
|
"choice": parse_choice,
|
|
"sequence": parse_sequence,
|
|
"labeled": parse_labeled,
|
|
"prefixed": parse_prefixed,
|
|
"suffixed": parse_suffixed,
|
|
"primary": parse_primary,
|
|
"action": parse_action,
|
|
"braced": parse_braced,
|
|
"nonBraceCharacters": parse_nonBraceCharacters,
|
|
"nonBraceCharacter": parse_nonBraceCharacter,
|
|
"equals": parse_equals,
|
|
"colon": parse_colon,
|
|
"semicolon": parse_semicolon,
|
|
"slash": parse_slash,
|
|
"and": parse_and,
|
|
"not": parse_not,
|
|
"question": parse_question,
|
|
"star": parse_star,
|
|
"plus": parse_plus,
|
|
"lparen": parse_lparen,
|
|
"rparen": parse_rparen,
|
|
"dot": parse_dot,
|
|
"identifier": parse_identifier,
|
|
"literal": parse_literal,
|
|
"string": parse_string,
|
|
"doubleQuotedString": parse_doubleQuotedString,
|
|
"doubleQuotedCharacter": parse_doubleQuotedCharacter,
|
|
"simpleDoubleQuotedCharacter": parse_simpleDoubleQuotedCharacter,
|
|
"singleQuotedString": parse_singleQuotedString,
|
|
"singleQuotedCharacter": parse_singleQuotedCharacter,
|
|
"simpleSingleQuotedCharacter": parse_simpleSingleQuotedCharacter,
|
|
"class": parse_class,
|
|
"classCharacterRange": parse_classCharacterRange,
|
|
"classCharacter": parse_classCharacter,
|
|
"bracketDelimitedCharacter": parse_bracketDelimitedCharacter,
|
|
"simpleBracketDelimitedCharacter": parse_simpleBracketDelimitedCharacter,
|
|
"simpleEscapeSequence": parse_simpleEscapeSequence,
|
|
"zeroEscapeSequence": parse_zeroEscapeSequence,
|
|
"hexEscapeSequence": parse_hexEscapeSequence,
|
|
"unicodeEscapeSequence": parse_unicodeEscapeSequence,
|
|
"eolEscapeSequence": parse_eolEscapeSequence,
|
|
"digit": parse_digit,
|
|
"hexDigit": parse_hexDigit,
|
|
"letter": parse_letter,
|
|
"lowerCaseLetter": parse_lowerCaseLetter,
|
|
"upperCaseLetter": parse_upperCaseLetter,
|
|
"__": parse___,
|
|
"comment": parse_comment,
|
|
"singleLineComment": parse_singleLineComment,
|
|
"multiLineComment": parse_multiLineComment,
|
|
"eol": parse_eol,
|
|
"eolChar": parse_eolChar,
|
|
"whitespace": parse_whitespace
|
|
};
|
|
|
|
if (startRule !== undefined) {
|
|
if (parseFunctions[startRule] === undefined) {
|
|
throw new Error("Invalid rule name: " + quote(startRule) + ".");
|
|
}
|
|
} else {
|
|
startRule = "grammar";
|
|
}
|
|
|
|
var pos = 0;
|
|
var reportFailures = 0;
|
|
var rightmostFailuresPos = 0;
|
|
var rightmostFailuresExpected = [];
|
|
|
|
function padLeft(input, padding, length) {
|
|
var result = input;
|
|
|
|
var padLength = length - input.length;
|
|
for (var i = 0; i < padLength; i++) {
|
|
result = padding + result;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
function escape(ch) {
|
|
var charCode = ch.charCodeAt(0);
|
|
var escapeChar;
|
|
var length;
|
|
|
|
if (charCode <= 0xFF) {
|
|
escapeChar = 'x';
|
|
length = 2;
|
|
} else {
|
|
escapeChar = 'u';
|
|
length = 4;
|
|
}
|
|
|
|
return '\\' + escapeChar + padLeft(charCode.toString(16).toUpperCase(), '0', length);
|
|
}
|
|
|
|
function matchFailed(failure) {
|
|
if (pos < rightmostFailuresPos) {
|
|
return;
|
|
}
|
|
|
|
if (pos > rightmostFailuresPos) {
|
|
rightmostFailuresPos = pos;
|
|
rightmostFailuresExpected = [];
|
|
}
|
|
|
|
rightmostFailuresExpected.push(failure);
|
|
}
|
|
|
|
function parse_grammar() {
|
|
var result0, result1, result2, result3;
|
|
var pos0, pos1;
|
|
|
|
pos0 = pos;
|
|
pos1 = pos;
|
|
result0 = parse___();
|
|
if (result0 !== null) {
|
|
result1 = parse_initializer();
|
|
result1 = result1 !== null ? result1 : "";
|
|
if (result1 !== null) {
|
|
result3 = parse_rule();
|
|
if (result3 !== null) {
|
|
result2 = [];
|
|
while (result3 !== null) {
|
|
result2.push(result3);
|
|
result3 = parse_rule();
|
|
}
|
|
} else {
|
|
result2 = null;
|
|
}
|
|
if (result2 !== null) {
|
|
result0 = [result0, result1, result2];
|
|
} else {
|
|
result0 = null;
|
|
pos = pos1;
|
|
}
|
|
} else {
|
|
result0 = null;
|
|
pos = pos1;
|
|
}
|
|
} else {
|
|
result0 = null;
|
|
pos = pos1;
|
|
}
|
|
if (result0 !== null) {
|
|
result0 = (function(offset, initializer, rules) {
|
|
return {
|
|
type: "grammar",
|
|
initializer: initializer !== "" ? initializer : null,
|
|
rules: rules,
|
|
startRule: rules[0].name
|
|
};
|
|
})(pos0, result0[1], result0[2]);
|
|
}
|
|
if (result0 === null) {
|
|
pos = pos0;
|
|
}
|
|
return result0;
|
|
}
|
|
|
|
function parse_initializer() {
|
|
var result0, result1;
|
|
var pos0, pos1;
|
|
|
|
pos0 = pos;
|
|
pos1 = pos;
|
|
result0 = parse_action();
|
|
if (result0 !== null) {
|
|
result1 = parse_semicolon();
|
|
result1 = result1 !== null ? result1 : "";
|
|
if (result1 !== null) {
|
|
result0 = [result0, result1];
|
|
} else {
|
|
result0 = null;
|
|
pos = pos1;
|
|
}
|
|
} else {
|
|
result0 = null;
|
|
pos = pos1;
|
|
}
|
|
if (result0 !== null) {
|
|
result0 = (function(offset, code) {
|
|
return {
|
|
type: "initializer",
|
|
code: code
|
|
};
|
|
})(pos0, result0[0]);
|
|
}
|
|
if (result0 === null) {
|
|
pos = pos0;
|
|
}
|
|
return result0;
|
|
}
|
|
|
|
function parse_rule() {
|
|
var result0, result1, result2, result3, result4;
|
|
var pos0, pos1;
|
|
|
|
pos0 = pos;
|
|
pos1 = pos;
|
|
result0 = parse_identifier();
|
|
if (result0 !== null) {
|
|
result1 = parse_string();
|
|
result1 = result1 !== null ? result1 : "";
|
|
if (result1 !== null) {
|
|
result2 = parse_equals();
|
|
if (result2 !== null) {
|
|
result3 = parse_choice();
|
|
if (result3 !== null) {
|
|
result4 = parse_semicolon();
|
|
result4 = result4 !== null ? result4 : "";
|
|
if (result4 !== null) {
|
|
result0 = [result0, result1, result2, result3, result4];
|
|
} else {
|
|
result0 = null;
|
|
pos = pos1;
|
|
}
|
|
} else {
|
|
result0 = null;
|
|
pos = pos1;
|
|
}
|
|
} else {
|
|
result0 = null;
|
|
pos = pos1;
|
|
}
|
|
} else {
|
|
result0 = null;
|
|
pos = pos1;
|
|
}
|
|
} else {
|
|
result0 = null;
|
|
pos = pos1;
|
|
}
|
|
if (result0 !== null) {
|
|
result0 = (function(offset, name, displayName, expression) {
|
|
return {
|
|
type: "rule",
|
|
name: name,
|
|
displayName: displayName !== "" ? displayName : null,
|
|
expression: expression
|
|
};
|
|
})(pos0, result0[0], result0[1], result0[3]);
|
|
}
|
|
if (result0 === null) {
|
|
pos = pos0;
|
|
}
|
|
return result0;
|
|
}
|
|
|
|
function parse_choice() {
|
|
var result0, result1, result2, result3;
|
|
var pos0, pos1, pos2;
|
|
|
|
pos0 = pos;
|
|
pos1 = pos;
|
|
result0 = parse_sequence();
|
|
if (result0 !== null) {
|
|
result1 = [];
|
|
pos2 = pos;
|
|
result2 = parse_slash();
|
|
if (result2 !== null) {
|
|
result3 = parse_sequence();
|
|
if (result3 !== null) {
|
|
result2 = [result2, result3];
|
|
} else {
|
|
result2 = null;
|
|
pos = pos2;
|
|
}
|
|
} else {
|
|
result2 = null;
|
|
pos = pos2;
|
|
}
|
|
while (result2 !== null) {
|
|
result1.push(result2);
|
|
pos2 = pos;
|
|
result2 = parse_slash();
|
|
if (result2 !== null) {
|
|
result3 = parse_sequence();
|
|
if (result3 !== null) {
|
|
result2 = [result2, result3];
|
|
} else {
|
|
result2 = null;
|
|
pos = pos2;
|
|
}
|
|
} else {
|
|
result2 = null;
|
|
pos = pos2;
|
|
}
|
|
}
|
|
if (result1 !== null) {
|
|
result0 = [result0, result1];
|
|
} else {
|
|
result0 = null;
|
|
pos = pos1;
|
|
}
|
|
} else {
|
|
result0 = null;
|
|
pos = pos1;
|
|
}
|
|
if (result0 !== null) {
|
|
result0 = (function(offset, head, tail) {
|
|
if (tail.length > 0) {
|
|
var alternatives = [head].concat(map(
|
|
tail,
|
|
function(element) { return element[1]; }
|
|
));
|
|
return {
|
|
type: "choice",
|
|
alternatives: alternatives
|
|
};
|
|
} else {
|
|
return head;
|
|
}
|
|
})(pos0, result0[0], result0[1]);
|
|
}
|
|
if (result0 === null) {
|
|
pos = pos0;
|
|
}
|
|
return result0;
|
|
}
|
|
|
|
function parse_sequence() {
|
|
var result0, result1;
|
|
var pos0, pos1;
|
|
|
|
pos0 = pos;
|
|
pos1 = pos;
|
|
result0 = [];
|
|
result1 = parse_labeled();
|
|
while (result1 !== null) {
|
|
result0.push(result1);
|
|
result1 = parse_labeled();
|
|
}
|
|
if (result0 !== null) {
|
|
result1 = parse_action();
|
|
if (result1 !== null) {
|
|
result0 = [result0, result1];
|
|
} else {
|
|
result0 = null;
|
|
pos = pos1;
|
|
}
|
|
} else {
|
|
result0 = null;
|
|
pos = pos1;
|
|
}
|
|
if (result0 !== null) {
|
|
result0 = (function(offset, elements, code) {
|
|
var expression = elements.length !== 1
|
|
? {
|
|
type: "sequence",
|
|
elements: elements
|
|
}
|
|
: elements[0];
|
|
return {
|
|
type: "action",
|
|
expression: expression,
|
|
code: code
|
|
};
|
|
})(pos0, result0[0], result0[1]);
|
|
}
|
|
if (result0 === null) {
|
|
pos = pos0;
|
|
}
|
|
if (result0 === null) {
|
|
pos0 = pos;
|
|
result0 = [];
|
|
result1 = parse_labeled();
|
|
while (result1 !== null) {
|
|
result0.push(result1);
|
|
result1 = parse_labeled();
|
|
}
|
|
if (result0 !== null) {
|
|
result0 = (function(offset, elements) {
|
|
return elements.length !== 1
|
|
? {
|
|
type: "sequence",
|
|
elements: elements
|
|
}
|
|
: elements[0];
|
|
})(pos0, result0);
|
|
}
|
|
if (result0 === null) {
|
|
pos = pos0;
|
|
}
|
|
}
|
|
return result0;
|
|
}
|
|
|
|
function parse_labeled() {
|
|
var result0, result1, result2;
|
|
var pos0, pos1;
|
|
|
|
pos0 = pos;
|
|
pos1 = pos;
|
|
result0 = parse_identifier();
|
|
if (result0 !== null) {
|
|
result1 = parse_colon();
|
|
if (result1 !== null) {
|
|
result2 = parse_prefixed();
|
|
if (result2 !== null) {
|
|
result0 = [result0, result1, result2];
|
|
} else {
|
|
result0 = null;
|
|
pos = pos1;
|
|
}
|
|
} else {
|
|
result0 = null;
|
|
pos = pos1;
|
|
}
|
|
} else {
|
|
result0 = null;
|
|
pos = pos1;
|
|
}
|
|
if (result0 !== null) {
|
|
result0 = (function(offset, label, expression) {
|
|
return {
|
|
type: "labeled",
|
|
label: label,
|
|
expression: expression
|
|
};
|
|
})(pos0, result0[0], result0[2]);
|
|
}
|
|
if (result0 === null) {
|
|
pos = pos0;
|
|
}
|
|
if (result0 === null) {
|
|
result0 = parse_prefixed();
|
|
}
|
|
return result0;
|
|
}
|
|
|
|
function parse_prefixed() {
|
|
var result0, result1;
|
|
var pos0, pos1;
|
|
|
|
pos0 = pos;
|
|
pos1 = pos;
|
|
result0 = parse_and();
|
|
if (result0 !== null) {
|
|
result1 = parse_action();
|
|
if (result1 !== null) {
|
|
result0 = [result0, result1];
|
|
} else {
|
|
result0 = null;
|
|
pos = pos1;
|
|
}
|
|
} else {
|
|
result0 = null;
|
|
pos = pos1;
|
|
}
|
|
if (result0 !== null) {
|
|
result0 = (function(offset, code) {
|
|
return {
|
|
type: "semantic_and",
|
|
code: code
|
|
};
|
|
})(pos0, result0[1]);
|
|
}
|
|
if (result0 === null) {
|
|
pos = pos0;
|
|
}
|
|
if (result0 === null) {
|
|
pos0 = pos;
|
|
pos1 = pos;
|
|
result0 = parse_and();
|
|
if (result0 !== null) {
|
|
result1 = parse_suffixed();
|
|
if (result1 !== null) {
|
|
result0 = [result0, result1];
|
|
} else {
|
|
result0 = null;
|
|
pos = pos1;
|
|
}
|
|
} else {
|
|
result0 = null;
|
|
pos = pos1;
|
|
}
|
|
if (result0 !== null) {
|
|
result0 = (function(offset, expression) {
|
|
return {
|
|
type: "simple_and",
|
|
expression: expression
|
|
};
|
|
})(pos0, result0[1]);
|
|
}
|
|
if (result0 === null) {
|
|
pos = pos0;
|
|
}
|
|
if (result0 === null) {
|
|
pos0 = pos;
|
|
pos1 = pos;
|
|
result0 = parse_not();
|
|
if (result0 !== null) {
|
|
result1 = parse_action();
|
|
if (result1 !== null) {
|
|
result0 = [result0, result1];
|
|
} else {
|
|
result0 = null;
|
|
pos = pos1;
|
|
}
|
|
} else {
|
|
result0 = null;
|
|
pos = pos1;
|
|
}
|
|
if (result0 !== null) {
|
|
result0 = (function(offset, code) {
|
|
return {
|
|
type: "semantic_not",
|
|
code: code
|
|
};
|
|
})(pos0, result0[1]);
|
|
}
|
|
if (result0 === null) {
|
|
pos = pos0;
|
|
}
|
|
if (result0 === null) {
|
|
pos0 = pos;
|
|
pos1 = pos;
|
|
result0 = parse_not();
|
|
if (result0 !== null) {
|
|
result1 = parse_suffixed();
|
|
if (result1 !== null) {
|
|
result0 = [result0, result1];
|
|
} else {
|
|
result0 = null;
|
|
pos = pos1;
|
|
}
|
|
} else {
|
|
result0 = null;
|
|
pos = pos1;
|
|
}
|
|
if (result0 !== null) {
|
|
result0 = (function(offset, expression) {
|
|
return {
|
|
type: "simple_not",
|
|
expression: expression
|
|
};
|
|
})(pos0, result0[1]);
|
|
}
|
|
if (result0 === null) {
|
|
pos = pos0;
|
|
}
|
|
if (result0 === null) {
|
|
result0 = parse_suffixed();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return result0;
|
|
}
|
|
|
|
function parse_suffixed() {
|
|
var result0, result1;
|
|
var pos0, pos1;
|
|
|
|
pos0 = pos;
|
|
pos1 = pos;
|
|
result0 = parse_primary();
|
|
if (result0 !== null) {
|
|
result1 = parse_question();
|
|
if (result1 !== null) {
|
|
result0 = [result0, result1];
|
|
} else {
|
|
result0 = null;
|
|
pos = pos1;
|
|
}
|
|
} else {
|
|
result0 = null;
|
|
pos = pos1;
|
|
}
|
|
if (result0 !== null) {
|
|
result0 = (function(offset, expression) {
|
|
return {
|
|
type: "optional",
|
|
expression: expression
|
|
};
|
|
})(pos0, result0[0]);
|
|
}
|
|
if (result0 === null) {
|
|
pos = pos0;
|
|
}
|
|
if (result0 === null) {
|
|
pos0 = pos;
|
|
pos1 = pos;
|
|
result0 = parse_primary();
|
|
if (result0 !== null) {
|
|
result1 = parse_star();
|
|
if (result1 !== null) {
|
|
result0 = [result0, result1];
|
|
} else {
|
|
result0 = null;
|
|
pos = pos1;
|
|
}
|
|
} else {
|
|
result0 = null;
|
|
pos = pos1;
|
|
}
|
|
if (result0 !== null) {
|
|
result0 = (function(offset, expression) {
|
|
return {
|
|
type: "zero_or_more",
|
|
expression: expression
|
|
};
|
|
})(pos0, result0[0]);
|
|
}
|
|
if (result0 === null) {
|
|
pos = pos0;
|
|
}
|
|
if (result0 === null) {
|
|
pos0 = pos;
|
|
pos1 = pos;
|
|
result0 = parse_primary();
|
|
if (result0 !== null) {
|
|
result1 = parse_plus();
|
|
if (result1 !== null) {
|
|
result0 = [result0, result1];
|
|
} else {
|
|
result0 = null;
|
|
pos = pos1;
|
|
}
|
|
} else {
|
|
result0 = null;
|
|
pos = pos1;
|
|
}
|
|
if (result0 !== null) {
|
|
result0 = (function(offset, expression) {
|
|
return {
|
|
type: "one_or_more",
|
|
expression: expression
|
|
};
|
|
})(pos0, result0[0]);
|
|
}
|
|
if (result0 === null) {
|
|
pos = pos0;
|
|
}
|
|
if (result0 === null) {
|
|
result0 = parse_primary();
|
|
}
|
|
}
|
|
}
|
|
return result0;
|
|
}
|
|
|
|
function parse_primary() {
|
|
var result0, result1, result2;
|
|
var pos0, pos1, pos2, pos3;
|
|
|
|
pos0 = pos;
|
|
pos1 = pos;
|
|
result0 = parse_identifier();
|
|
if (result0 !== null) {
|
|
pos2 = pos;
|
|
reportFailures++;
|
|
pos3 = pos;
|
|
result1 = parse_string();
|
|
result1 = result1 !== null ? result1 : "";
|
|
if (result1 !== null) {
|
|
result2 = parse_equals();
|
|
if (result2 !== null) {
|
|
result1 = [result1, result2];
|
|
} else {
|
|
result1 = null;
|
|
pos = pos3;
|
|
}
|
|
} else {
|
|
result1 = null;
|
|
pos = pos3;
|
|
}
|
|
reportFailures--;
|
|
if (result1 === null) {
|
|
result1 = "";
|
|
} else {
|
|
result1 = null;
|
|
pos = pos2;
|
|
}
|
|
if (result1 !== null) {
|
|
result0 = [result0, result1];
|
|
} else {
|
|
result0 = null;
|
|
pos = pos1;
|
|
}
|
|
} else {
|
|
result0 = null;
|
|
pos = pos1;
|
|
}
|
|
if (result0 !== null) {
|
|
result0 = (function(offset, name) {
|
|
return {
|
|
type: "rule_ref",
|
|
name: name
|
|
};
|
|
})(pos0, result0[0]);
|
|
}
|
|
if (result0 === null) {
|
|
pos = pos0;
|
|
}
|
|
if (result0 === null) {
|
|
result0 = parse_literal();
|
|
if (result0 === null) {
|
|
pos0 = pos;
|
|
result0 = parse_dot();
|
|
if (result0 !== null) {
|
|
result0 = (function(offset) { return { type: "any" }; })(pos0);
|
|
}
|
|
if (result0 === null) {
|
|
pos = pos0;
|
|
}
|
|
if (result0 === null) {
|
|
result0 = parse_class();
|
|
if (result0 === null) {
|
|
pos0 = pos;
|
|
pos1 = pos;
|
|
result0 = parse_lparen();
|
|
if (result0 !== null) {
|
|
result1 = parse_choice();
|
|
if (result1 !== null) {
|
|
result2 = parse_rparen();
|
|
if (result2 !== null) {
|
|
result0 = [result0, result1, result2];
|
|
} else {
|
|
result0 = null;
|
|
pos = pos1;
|
|
}
|
|
} else {
|
|
result0 = null;
|
|
pos = pos1;
|
|
}
|
|
} else {
|
|
result0 = null;
|
|
pos = pos1;
|
|
}
|
|
if (result0 !== null) {
|
|
result0 = (function(offset, expression) { return expression; })(pos0, result0[1]);
|
|
}
|
|
if (result0 === null) {
|
|
pos = pos0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return result0;
|
|
}
|
|
|
|
function parse_action() {
|
|
var result0, result1;
|
|
var pos0, pos1;
|
|
|
|
reportFailures++;
|
|
pos0 = pos;
|
|
pos1 = pos;
|
|
result0 = parse_braced();
|
|
if (result0 !== null) {
|
|
result1 = parse___();
|
|
if (result1 !== null) {
|
|
result0 = [result0, result1];
|
|
} else {
|
|
result0 = null;
|
|
pos = pos1;
|
|
}
|
|
} else {
|
|
result0 = null;
|
|
pos = pos1;
|
|
}
|
|
if (result0 !== null) {
|
|
result0 = (function(offset, braced) { return braced.substr(1, braced.length - 2); })(pos0, result0[0]);
|
|
}
|
|
if (result0 === null) {
|
|
pos = pos0;
|
|
}
|
|
reportFailures--;
|
|
if (reportFailures === 0 && result0 === null) {
|
|
matchFailed("action");
|
|
}
|
|
return result0;
|
|
}
|
|
|
|
function parse_braced() {
|
|
var result0, result1, result2;
|
|
var pos0, pos1;
|
|
|
|
pos0 = pos;
|
|
pos1 = pos;
|
|
if (input.charCodeAt(pos) === 123) {
|
|
result0 = "{";
|
|
pos++;
|
|
} else {
|
|
result0 = null;
|
|
if (reportFailures === 0) {
|
|
matchFailed("\"{\"");
|
|
}
|
|
}
|
|
if (result0 !== null) {
|
|
result1 = [];
|
|
result2 = parse_braced();
|
|
if (result2 === null) {
|
|
result2 = parse_nonBraceCharacter();
|
|
}
|
|
while (result2 !== null) {
|
|
result1.push(result2);
|
|
result2 = parse_braced();
|
|
if (result2 === null) {
|
|
result2 = parse_nonBraceCharacter();
|
|
}
|
|
}
|
|
if (result1 !== null) {
|
|
if (input.charCodeAt(pos) === 125) {
|
|
result2 = "}";
|
|
pos++;
|
|
} else {
|
|
result2 = null;
|
|
if (reportFailures === 0) {
|
|
matchFailed("\"}\"");
|
|
}
|
|
}
|
|
if (result2 !== null) {
|
|
result0 = [result0, result1, result2];
|
|
} else {
|
|
result0 = null;
|
|
pos = pos1;
|
|
}
|
|
} else {
|
|
result0 = null;
|
|
pos = pos1;
|
|
}
|
|
} else {
|
|
result0 = null;
|
|
pos = pos1;
|
|
}
|
|
if (result0 !== null) {
|
|
result0 = (function(offset, parts) {
|
|
return "{" + parts.join("") + "}";
|
|
})(pos0, result0[1]);
|
|
}
|
|
if (result0 === null) {
|
|
pos = pos0;
|
|
}
|
|
return result0;
|
|
}
|
|
|
|
function parse_nonBraceCharacters() {
|
|
var result0, result1;
|
|
var pos0;
|
|
|
|
pos0 = pos;
|
|
result1 = parse_nonBraceCharacter();
|
|
if (result1 !== null) {
|
|
result0 = [];
|
|
while (result1 !== null) {
|
|
result0.push(result1);
|
|
result1 = parse_nonBraceCharacter();
|
|
}
|
|
} else {
|
|
result0 = null;
|
|
}
|
|
if (result0 !== null) {
|
|
result0 = (function(offset, chars) { return chars.join(""); })(pos0, result0);
|
|
}
|
|
if (result0 === null) {
|
|
pos = pos0;
|
|
}
|
|
return result0;
|
|
}
|
|
|
|
function parse_nonBraceCharacter() {
|
|
var result0;
|
|
|
|
if (/^[^{}]/.test(input.charAt(pos))) {
|
|
result0 = input.charAt(pos);
|
|
pos++;
|
|
} else {
|
|
result0 = null;
|
|
if (reportFailures === 0) {
|
|
matchFailed("[^{}]");
|
|
}
|
|
}
|
|
return result0;
|
|
}
|
|
|
|
function parse_equals() {
|
|
var result0, result1;
|
|
var pos0, pos1;
|
|
|
|
pos0 = pos;
|
|
pos1 = pos;
|
|
if (input.charCodeAt(pos) === 61) {
|
|
result0 = "=";
|
|
pos++;
|
|
} else {
|
|
result0 = null;
|
|
if (reportFailures === 0) {
|
|
matchFailed("\"=\"");
|
|
}
|
|
}
|
|
if (result0 !== null) {
|
|
result1 = parse___();
|
|
if (result1 !== null) {
|
|
result0 = [result0, result1];
|
|
} else {
|
|
result0 = null;
|
|
pos = pos1;
|
|
}
|
|
} else {
|
|
result0 = null;
|
|
pos = pos1;
|
|
}
|
|
if (result0 !== null) {
|
|
result0 = (function(offset) { return "="; })(pos0);
|
|
}
|
|
if (result0 === null) {
|
|
pos = pos0;
|
|
}
|
|
return result0;
|
|
}
|
|
|
|
function parse_colon() {
|
|
var result0, result1;
|
|
var pos0, pos1;
|
|
|
|
pos0 = pos;
|
|
pos1 = pos;
|
|
if (input.charCodeAt(pos) === 58) {
|
|
result0 = ":";
|
|
pos++;
|
|
} else {
|
|
result0 = null;
|
|
if (reportFailures === 0) {
|
|
matchFailed("\":\"");
|
|
}
|
|
}
|
|
if (result0 !== null) {
|
|
result1 = parse___();
|
|
if (result1 !== null) {
|
|
result0 = [result0, result1];
|
|
} else {
|
|
result0 = null;
|
|
pos = pos1;
|
|
}
|
|
} else {
|
|
result0 = null;
|
|
pos = pos1;
|
|
}
|
|
if (result0 !== null) {
|
|
result0 = (function(offset) { return ":"; })(pos0);
|
|
}
|
|
if (result0 === null) {
|
|
pos = pos0;
|
|
}
|
|
return result0;
|
|
}
|
|
|
|
function parse_semicolon() {
|
|
var result0, result1;
|
|
var pos0, pos1;
|
|
|
|
pos0 = pos;
|
|
pos1 = pos;
|
|
if (input.charCodeAt(pos) === 59) {
|
|
result0 = ";";
|
|
pos++;
|
|
} else {
|
|
result0 = null;
|
|
if (reportFailures === 0) {
|
|
matchFailed("\";\"");
|
|
}
|
|
}
|
|
if (result0 !== null) {
|
|
result1 = parse___();
|
|
if (result1 !== null) {
|
|
result0 = [result0, result1];
|
|
} else {
|
|
result0 = null;
|
|
pos = pos1;
|
|
}
|
|
} else {
|
|
result0 = null;
|
|
pos = pos1;
|
|
}
|
|
if (result0 !== null) {
|
|
result0 = (function(offset) { return ";"; })(pos0);
|
|
}
|
|
if (result0 === null) {
|
|
pos = pos0;
|
|
}
|
|
return result0;
|
|
}
|
|
|
|
function parse_slash() {
|
|
var result0, result1;
|
|
var pos0, pos1;
|
|
|
|
pos0 = pos;
|
|
pos1 = pos;
|
|
if (input.charCodeAt(pos) === 47) {
|
|
result0 = "/";
|
|
pos++;
|
|
} else {
|
|
result0 = null;
|
|
if (reportFailures === 0) {
|
|
matchFailed("\"/\"");
|
|
}
|
|
}
|
|
if (result0 !== null) {
|
|
result1 = parse___();
|
|
if (result1 !== null) {
|
|
result0 = [result0, result1];
|
|
} else {
|
|
result0 = null;
|
|
pos = pos1;
|
|
}
|
|
} else {
|
|
result0 = null;
|
|
pos = pos1;
|
|
}
|
|
if (result0 !== null) {
|
|
result0 = (function(offset) { return "/"; })(pos0);
|
|
}
|
|
if (result0 === null) {
|
|
pos = pos0;
|
|
}
|
|
return result0;
|
|
}
|
|
|
|
function parse_and() {
|
|
var result0, result1;
|
|
var pos0, pos1;
|
|
|
|
pos0 = pos;
|
|
pos1 = pos;
|
|
if (input.charCodeAt(pos) === 38) {
|
|
result0 = "&";
|
|
pos++;
|
|
} else {
|
|
result0 = null;
|
|
if (reportFailures === 0) {
|
|
matchFailed("\"&\"");
|
|
}
|
|
}
|
|
if (result0 !== null) {
|
|
result1 = parse___();
|
|
if (result1 !== null) {
|
|
result0 = [result0, result1];
|
|
} else {
|
|
result0 = null;
|
|
pos = pos1;
|
|
}
|
|
} else {
|
|
result0 = null;
|
|
pos = pos1;
|
|
}
|
|
if (result0 !== null) {
|
|
result0 = (function(offset) { return "&"; })(pos0);
|
|
}
|
|
if (result0 === null) {
|
|
pos = pos0;
|
|
}
|
|
return result0;
|
|
}
|
|
|
|
function parse_not() {
|
|
var result0, result1;
|
|
var pos0, pos1;
|
|
|
|
pos0 = pos;
|
|
pos1 = pos;
|
|
if (input.charCodeAt(pos) === 33) {
|
|
result0 = "!";
|
|
pos++;
|
|
} else {
|
|
result0 = null;
|
|
if (reportFailures === 0) {
|
|
matchFailed("\"!\"");
|
|
}
|
|
}
|
|
if (result0 !== null) {
|
|
result1 = parse___();
|
|
if (result1 !== null) {
|
|
result0 = [result0, result1];
|
|
} else {
|
|
result0 = null;
|
|
pos = pos1;
|
|
}
|
|
} else {
|
|
result0 = null;
|
|
pos = pos1;
|
|
}
|
|
if (result0 !== null) {
|
|
result0 = (function(offset) { return "!"; })(pos0);
|
|
}
|
|
if (result0 === null) {
|
|
pos = pos0;
|
|
}
|
|
return result0;
|
|
}
|
|
|
|
function parse_question() {
|
|
var result0, result1;
|
|
var pos0, pos1;
|
|
|
|
pos0 = pos;
|
|
pos1 = pos;
|
|
if (input.charCodeAt(pos) === 63) {
|
|
result0 = "?";
|
|
pos++;
|
|
} else {
|
|
result0 = null;
|
|
if (reportFailures === 0) {
|
|
matchFailed("\"?\"");
|
|
}
|
|
}
|
|
if (result0 !== null) {
|
|
result1 = parse___();
|
|
if (result1 !== null) {
|
|
result0 = [result0, result1];
|
|
} else {
|
|
result0 = null;
|
|
pos = pos1;
|
|
}
|
|
} else {
|
|
result0 = null;
|
|
pos = pos1;
|
|
}
|
|
if (result0 !== null) {
|
|
result0 = (function(offset) { return "?"; })(pos0);
|
|
}
|
|
if (result0 === null) {
|
|
pos = pos0;
|
|
}
|
|
return result0;
|
|
}
|
|
|
|
function parse_star() {
|
|
var result0, result1;
|
|
var pos0, pos1;
|
|
|
|
pos0 = pos;
|
|
pos1 = pos;
|
|
if (input.charCodeAt(pos) === 42) {
|
|
result0 = "*";
|
|
pos++;
|
|
} else {
|
|
result0 = null;
|
|
if (reportFailures === 0) {
|
|
matchFailed("\"*\"");
|
|
}
|
|
}
|
|
if (result0 !== null) {
|
|
result1 = parse___();
|
|
if (result1 !== null) {
|
|
result0 = [result0, result1];
|
|
} else {
|
|
result0 = null;
|
|
pos = pos1;
|
|
}
|
|
} else {
|
|
result0 = null;
|
|
pos = pos1;
|
|
}
|
|
if (result0 !== null) {
|
|
result0 = (function(offset) { return "*"; })(pos0);
|
|
}
|
|
if (result0 === null) {
|
|
pos = pos0;
|
|
}
|
|
return result0;
|
|
}
|
|
|
|
function parse_plus() {
|
|
var result0, result1;
|
|
var pos0, pos1;
|
|
|
|
pos0 = pos;
|
|
pos1 = pos;
|
|
if (input.charCodeAt(pos) === 43) {
|
|
result0 = "+";
|
|
pos++;
|
|
} else {
|
|
result0 = null;
|
|
if (reportFailures === 0) {
|
|
matchFailed("\"+\"");
|
|
}
|
|
}
|
|
if (result0 !== null) {
|
|
result1 = parse___();
|
|
if (result1 !== null) {
|
|
result0 = [result0, result1];
|
|
} else {
|
|
result0 = null;
|
|
pos = pos1;
|
|
}
|
|
} else {
|
|
result0 = null;
|
|
pos = pos1;
|
|
}
|
|
if (result0 !== null) {
|
|
result0 = (function(offset) { return "+"; })(pos0);
|
|
}
|
|
if (result0 === null) {
|
|
pos = pos0;
|
|
}
|
|
return result0;
|
|
}
|
|
|
|
function parse_lparen() {
|
|
var result0, result1;
|
|
var pos0, pos1;
|
|
|
|
pos0 = pos;
|
|
pos1 = pos;
|
|
if (input.charCodeAt(pos) === 40) {
|
|
result0 = "(";
|
|
pos++;
|
|
} else {
|
|
result0 = null;
|
|
if (reportFailures === 0) {
|
|
matchFailed("\"(\"");
|
|
}
|
|
}
|
|
if (result0 !== null) {
|
|
result1 = parse___();
|
|
if (result1 !== null) {
|
|
result0 = [result0, result1];
|
|
} else {
|
|
result0 = null;
|
|
pos = pos1;
|
|
}
|
|
} else {
|
|
result0 = null;
|
|
pos = pos1;
|
|
}
|
|
if (result0 !== null) {
|
|
result0 = (function(offset) { return "("; })(pos0);
|
|
}
|
|
if (result0 === null) {
|
|
pos = pos0;
|
|
}
|
|
return result0;
|
|
}
|
|
|
|
function parse_rparen() {
|
|
var result0, result1;
|
|
var pos0, pos1;
|
|
|
|
pos0 = pos;
|
|
pos1 = pos;
|
|
if (input.charCodeAt(pos) === 41) {
|
|
result0 = ")";
|
|
pos++;
|
|
} else {
|
|
result0 = null;
|
|
if (reportFailures === 0) {
|
|
matchFailed("\")\"");
|
|
}
|
|
}
|
|
if (result0 !== null) {
|
|
result1 = parse___();
|
|
if (result1 !== null) {
|
|
result0 = [result0, result1];
|
|
} else {
|
|
result0 = null;
|
|
pos = pos1;
|
|
}
|
|
} else {
|
|
result0 = null;
|
|
pos = pos1;
|
|
}
|
|
if (result0 !== null) {
|
|
result0 = (function(offset) { return ")"; })(pos0);
|
|
}
|
|
if (result0 === null) {
|
|
pos = pos0;
|
|
}
|
|
return result0;
|
|
}
|
|
|
|
function parse_dot() {
|
|
var result0, result1;
|
|
var pos0, pos1;
|
|
|
|
pos0 = pos;
|
|
pos1 = pos;
|
|
if (input.charCodeAt(pos) === 46) {
|
|
result0 = ".";
|
|
pos++;
|
|
} else {
|
|
result0 = null;
|
|
if (reportFailures === 0) {
|
|
matchFailed("\".\"");
|
|
}
|
|
}
|
|
if (result0 !== null) {
|
|
result1 = parse___();
|
|
if (result1 !== null) {
|
|
result0 = [result0, result1];
|
|
} else {
|
|
result0 = null;
|
|
pos = pos1;
|
|
}
|
|
} else {
|
|
result0 = null;
|
|
pos = pos1;
|
|
}
|
|
if (result0 !== null) {
|
|
result0 = (function(offset) { return "."; })(pos0);
|
|
}
|
|
if (result0 === null) {
|
|
pos = pos0;
|
|
}
|
|
return result0;
|
|
}
|
|
|
|
function parse_identifier() {
|
|
var result0, result1, result2;
|
|
var pos0, pos1;
|
|
|
|
reportFailures++;
|
|
pos0 = pos;
|
|
pos1 = pos;
|
|
result0 = parse_letter();
|
|
if (result0 === null) {
|
|
if (input.charCodeAt(pos) === 95) {
|
|
result0 = "_";
|
|
pos++;
|
|
} else {
|
|
result0 = null;
|
|
if (reportFailures === 0) {
|
|
matchFailed("\"_\"");
|
|
}
|
|
}
|
|
if (result0 === null) {
|
|
if (input.charCodeAt(pos) === 36) {
|
|
result0 = "$";
|
|
pos++;
|
|
} else {
|
|
result0 = null;
|
|
if (reportFailures === 0) {
|
|
matchFailed("\"$\"");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (result0 !== null) {
|
|
result1 = [];
|
|
result2 = parse_letter();
|
|
if (result2 === null) {
|
|
result2 = parse_digit();
|
|
if (result2 === null) {
|
|
if (input.charCodeAt(pos) === 95) {
|
|
result2 = "_";
|
|
pos++;
|
|
} else {
|
|
result2 = null;
|
|
if (reportFailures === 0) {
|
|
matchFailed("\"_\"");
|
|
}
|
|
}
|
|
if (result2 === null) {
|
|
if (input.charCodeAt(pos) === 36) {
|
|
result2 = "$";
|
|
pos++;
|
|
} else {
|
|
result2 = null;
|
|
if (reportFailures === 0) {
|
|
matchFailed("\"$\"");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
while (result2 !== null) {
|
|
result1.push(result2);
|
|
result2 = parse_letter();
|
|
if (result2 === null) {
|
|
result2 = parse_digit();
|
|
if (result2 === null) {
|
|
if (input.charCodeAt(pos) === 95) {
|
|
result2 = "_";
|
|
pos++;
|
|
} else {
|
|
result2 = null;
|
|
if (reportFailures === 0) {
|
|
matchFailed("\"_\"");
|
|
}
|
|
}
|
|
if (result2 === null) {
|
|
if (input.charCodeAt(pos) === 36) {
|
|
result2 = "$";
|
|
pos++;
|
|
} else {
|
|
result2 = null;
|
|
if (reportFailures === 0) {
|
|
matchFailed("\"$\"");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (result1 !== null) {
|
|
result2 = parse___();
|
|
if (result2 !== null) {
|
|
result0 = [result0, result1, result2];
|
|
} else {
|
|
result0 = null;
|
|
pos = pos1;
|
|
}
|
|
} else {
|
|
result0 = null;
|
|
pos = pos1;
|
|
}
|
|
} else {
|
|
result0 = null;
|
|
pos = pos1;
|
|
}
|
|
if (result0 !== null) {
|
|
result0 = (function(offset, head, tail) {
|
|
return head + tail.join("");
|
|
})(pos0, result0[0], result0[1]);
|
|
}
|
|
if (result0 === null) {
|
|
pos = pos0;
|
|
}
|
|
reportFailures--;
|
|
if (reportFailures === 0 && result0 === null) {
|
|
matchFailed("identifier");
|
|
}
|
|
return result0;
|
|
}
|
|
|
|
function parse_literal() {
|
|
var result0, result1, result2;
|
|
var pos0, pos1;
|
|
|
|
reportFailures++;
|
|
pos0 = pos;
|
|
pos1 = pos;
|
|
result0 = parse_doubleQuotedString();
|
|
if (result0 === null) {
|
|
result0 = parse_singleQuotedString();
|
|
}
|
|
if (result0 !== null) {
|
|
if (input.charCodeAt(pos) === 105) {
|
|
result1 = "i";
|
|
pos++;
|
|
} else {
|
|
result1 = null;
|
|
if (reportFailures === 0) {
|
|
matchFailed("\"i\"");
|
|
}
|
|
}
|
|
result1 = result1 !== null ? result1 : "";
|
|
if (result1 !== null) {
|
|
result2 = parse___();
|
|
if (result2 !== null) {
|
|
result0 = [result0, result1, result2];
|
|
} else {
|
|
result0 = null;
|
|
pos = pos1;
|
|
}
|
|
} else {
|
|
result0 = null;
|
|
pos = pos1;
|
|
}
|
|
} else {
|
|
result0 = null;
|
|
pos = pos1;
|
|
}
|
|
if (result0 !== null) {
|
|
result0 = (function(offset, value, flags) {
|
|
return {
|
|
type: "literal",
|
|
value: value,
|
|
ignoreCase: flags === "i"
|
|
};
|
|
})(pos0, result0[0], result0[1]);
|
|
}
|
|
if (result0 === null) {
|
|
pos = pos0;
|
|
}
|
|
reportFailures--;
|
|
if (reportFailures === 0 && result0 === null) {
|
|
matchFailed("literal");
|
|
}
|
|
return result0;
|
|
}
|
|
|
|
function parse_string() {
|
|
var result0, result1;
|
|
var pos0, pos1;
|
|
|
|
reportFailures++;
|
|
pos0 = pos;
|
|
pos1 = pos;
|
|
result0 = parse_doubleQuotedString();
|
|
if (result0 === null) {
|
|
result0 = parse_singleQuotedString();
|
|
}
|
|
if (result0 !== null) {
|
|
result1 = parse___();
|
|
if (result1 !== null) {
|
|
result0 = [result0, result1];
|
|
} else {
|
|
result0 = null;
|
|
pos = pos1;
|
|
}
|
|
} else {
|
|
result0 = null;
|
|
pos = pos1;
|
|
}
|
|
if (result0 !== null) {
|
|
result0 = (function(offset, string) { return string; })(pos0, result0[0]);
|
|
}
|
|
if (result0 === null) {
|
|
pos = pos0;
|
|
}
|
|
reportFailures--;
|
|
if (reportFailures === 0 && result0 === null) {
|
|
matchFailed("string");
|
|
}
|
|
return result0;
|
|
}
|
|
|
|
function parse_doubleQuotedString() {
|
|
var result0, result1, result2;
|
|
var pos0, pos1;
|
|
|
|
pos0 = pos;
|
|
pos1 = pos;
|
|
if (input.charCodeAt(pos) === 34) {
|
|
result0 = "\"";
|
|
pos++;
|
|
} else {
|
|
result0 = null;
|
|
if (reportFailures === 0) {
|
|
matchFailed("\"\\\"\"");
|
|
}
|
|
}
|
|
if (result0 !== null) {
|
|
result1 = [];
|
|
result2 = parse_doubleQuotedCharacter();
|
|
while (result2 !== null) {
|
|
result1.push(result2);
|
|
result2 = parse_doubleQuotedCharacter();
|
|
}
|
|
if (result1 !== null) {
|
|
if (input.charCodeAt(pos) === 34) {
|
|
result2 = "\"";
|
|
pos++;
|
|
} else {
|
|
result2 = null;
|
|
if (reportFailures === 0) {
|
|
matchFailed("\"\\\"\"");
|
|
}
|
|
}
|
|
if (result2 !== null) {
|
|
result0 = [result0, result1, result2];
|
|
} else {
|
|
result0 = null;
|
|
pos = pos1;
|
|
}
|
|
} else {
|
|
result0 = null;
|
|
pos = pos1;
|
|
}
|
|
} else {
|
|
result0 = null;
|
|
pos = pos1;
|
|
}
|
|
if (result0 !== null) {
|
|
result0 = (function(offset, chars) { return chars.join(""); })(pos0, result0[1]);
|
|
}
|
|
if (result0 === null) {
|
|
pos = pos0;
|
|
}
|
|
return result0;
|
|
}
|
|
|
|
function parse_doubleQuotedCharacter() {
|
|
var result0;
|
|
|
|
result0 = parse_simpleDoubleQuotedCharacter();
|
|
if (result0 === null) {
|
|
result0 = parse_simpleEscapeSequence();
|
|
if (result0 === null) {
|
|
result0 = parse_zeroEscapeSequence();
|
|
if (result0 === null) {
|
|
result0 = parse_hexEscapeSequence();
|
|
if (result0 === null) {
|
|
result0 = parse_unicodeEscapeSequence();
|
|
if (result0 === null) {
|
|
result0 = parse_eolEscapeSequence();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return result0;
|
|
}
|
|
|
|
function parse_simpleDoubleQuotedCharacter() {
|
|
var result0, result1;
|
|
var pos0, pos1, pos2;
|
|
|
|
pos0 = pos;
|
|
pos1 = pos;
|
|
pos2 = pos;
|
|
reportFailures++;
|
|
if (input.charCodeAt(pos) === 34) {
|
|
result0 = "\"";
|
|
pos++;
|
|
} else {
|
|
result0 = null;
|
|
if (reportFailures === 0) {
|
|
matchFailed("\"\\\"\"");
|
|
}
|
|
}
|
|
if (result0 === null) {
|
|
if (input.charCodeAt(pos) === 92) {
|
|
result0 = "\\";
|
|
pos++;
|
|
} else {
|
|
result0 = null;
|
|
if (reportFailures === 0) {
|
|
matchFailed("\"\\\\\"");
|
|
}
|
|
}
|
|
if (result0 === null) {
|
|
result0 = parse_eolChar();
|
|
}
|
|
}
|
|
reportFailures--;
|
|
if (result0 === null) {
|
|
result0 = "";
|
|
} else {
|
|
result0 = null;
|
|
pos = pos2;
|
|
}
|
|
if (result0 !== null) {
|
|
if (input.length > pos) {
|
|
result1 = input.charAt(pos);
|
|
pos++;
|
|
} else {
|
|
result1 = null;
|
|
if (reportFailures === 0) {
|
|
matchFailed("any character");
|
|
}
|
|
}
|
|
if (result1 !== null) {
|
|
result0 = [result0, result1];
|
|
} else {
|
|
result0 = null;
|
|
pos = pos1;
|
|
}
|
|
} else {
|
|
result0 = null;
|
|
pos = pos1;
|
|
}
|
|
if (result0 !== null) {
|
|
result0 = (function(offset, char_) { return char_; })(pos0, result0[1]);
|
|
}
|
|
if (result0 === null) {
|
|
pos = pos0;
|
|
}
|
|
return result0;
|
|
}
|
|
|
|
function parse_singleQuotedString() {
|
|
var result0, result1, result2;
|
|
var pos0, pos1;
|
|
|
|
pos0 = pos;
|
|
pos1 = pos;
|
|
if (input.charCodeAt(pos) === 39) {
|
|
result0 = "'";
|
|
pos++;
|
|
} else {
|
|
result0 = null;
|
|
if (reportFailures === 0) {
|
|
matchFailed("\"'\"");
|
|
}
|
|
}
|
|
if (result0 !== null) {
|
|
result1 = [];
|
|
result2 = parse_singleQuotedCharacter();
|
|
while (result2 !== null) {
|
|
result1.push(result2);
|
|
result2 = parse_singleQuotedCharacter();
|
|
}
|
|
if (result1 !== null) {
|
|
if (input.charCodeAt(pos) === 39) {
|
|
result2 = "'";
|
|
pos++;
|
|
} else {
|
|
result2 = null;
|
|
if (reportFailures === 0) {
|
|
matchFailed("\"'\"");
|
|
}
|
|
}
|
|
if (result2 !== null) {
|
|
result0 = [result0, result1, result2];
|
|
} else {
|
|
result0 = null;
|
|
pos = pos1;
|
|
}
|
|
} else {
|
|
result0 = null;
|
|
pos = pos1;
|
|
}
|
|
} else {
|
|
result0 = null;
|
|
pos = pos1;
|
|
}
|
|
if (result0 !== null) {
|
|
result0 = (function(offset, chars) { return chars.join(""); })(pos0, result0[1]);
|
|
}
|
|
if (result0 === null) {
|
|
pos = pos0;
|
|
}
|
|
return result0;
|
|
}
|
|
|
|
function parse_singleQuotedCharacter() {
|
|
var result0;
|
|
|
|
result0 = parse_simpleSingleQuotedCharacter();
|
|
if (result0 === null) {
|
|
result0 = parse_simpleEscapeSequence();
|
|
if (result0 === null) {
|
|
result0 = parse_zeroEscapeSequence();
|
|
if (result0 === null) {
|
|
result0 = parse_hexEscapeSequence();
|
|
if (result0 === null) {
|
|
result0 = parse_unicodeEscapeSequence();
|
|
if (result0 === null) {
|
|
result0 = parse_eolEscapeSequence();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return result0;
|
|
}
|
|
|
|
function parse_simpleSingleQuotedCharacter() {
|
|
var result0, result1;
|
|
var pos0, pos1, pos2;
|
|
|
|
pos0 = pos;
|
|
pos1 = pos;
|
|
pos2 = pos;
|
|
reportFailures++;
|
|
if (input.charCodeAt(pos) === 39) {
|
|
result0 = "'";
|
|
pos++;
|
|
} else {
|
|
result0 = null;
|
|
if (reportFailures === 0) {
|
|
matchFailed("\"'\"");
|
|
}
|
|
}
|
|
if (result0 === null) {
|
|
if (input.charCodeAt(pos) === 92) {
|
|
result0 = "\\";
|
|
pos++;
|
|
} else {
|
|
result0 = null;
|
|
if (reportFailures === 0) {
|
|
matchFailed("\"\\\\\"");
|
|
}
|
|
}
|
|
if (result0 === null) {
|
|
result0 = parse_eolChar();
|
|
}
|
|
}
|
|
reportFailures--;
|
|
if (result0 === null) {
|
|
result0 = "";
|
|
} else {
|
|
result0 = null;
|
|
pos = pos2;
|
|
}
|
|
if (result0 !== null) {
|
|
if (input.length > pos) {
|
|
result1 = input.charAt(pos);
|
|
pos++;
|
|
} else {
|
|
result1 = null;
|
|
if (reportFailures === 0) {
|
|
matchFailed("any character");
|
|
}
|
|
}
|
|
if (result1 !== null) {
|
|
result0 = [result0, result1];
|
|
} else {
|
|
result0 = null;
|
|
pos = pos1;
|
|
}
|
|
} else {
|
|
result0 = null;
|
|
pos = pos1;
|
|
}
|
|
if (result0 !== null) {
|
|
result0 = (function(offset, char_) { return char_; })(pos0, result0[1]);
|
|
}
|
|
if (result0 === null) {
|
|
pos = pos0;
|
|
}
|
|
return result0;
|
|
}
|
|
|
|
function parse_class() {
|
|
var result0, result1, result2, result3, result4, result5;
|
|
var pos0, pos1;
|
|
|
|
reportFailures++;
|
|
pos0 = pos;
|
|
pos1 = pos;
|
|
if (input.charCodeAt(pos) === 91) {
|
|
result0 = "[";
|
|
pos++;
|
|
} else {
|
|
result0 = null;
|
|
if (reportFailures === 0) {
|
|
matchFailed("\"[\"");
|
|
}
|
|
}
|
|
if (result0 !== null) {
|
|
if (input.charCodeAt(pos) === 94) {
|
|
result1 = "^";
|
|
pos++;
|
|
} else {
|
|
result1 = null;
|
|
if (reportFailures === 0) {
|
|
matchFailed("\"^\"");
|
|
}
|
|
}
|
|
result1 = result1 !== null ? result1 : "";
|
|
if (result1 !== null) {
|
|
result2 = [];
|
|
result3 = parse_classCharacterRange();
|
|
if (result3 === null) {
|
|
result3 = parse_classCharacter();
|
|
}
|
|
while (result3 !== null) {
|
|
result2.push(result3);
|
|
result3 = parse_classCharacterRange();
|
|
if (result3 === null) {
|
|
result3 = parse_classCharacter();
|
|
}
|
|
}
|
|
if (result2 !== null) {
|
|
if (input.charCodeAt(pos) === 93) {
|
|
result3 = "]";
|
|
pos++;
|
|
} else {
|
|
result3 = null;
|
|
if (reportFailures === 0) {
|
|
matchFailed("\"]\"");
|
|
}
|
|
}
|
|
if (result3 !== null) {
|
|
if (input.charCodeAt(pos) === 105) {
|
|
result4 = "i";
|
|
pos++;
|
|
} else {
|
|
result4 = null;
|
|
if (reportFailures === 0) {
|
|
matchFailed("\"i\"");
|
|
}
|
|
}
|
|
result4 = result4 !== null ? result4 : "";
|
|
if (result4 !== null) {
|
|
result5 = parse___();
|
|
if (result5 !== null) {
|
|
result0 = [result0, result1, result2, result3, result4, result5];
|
|
} else {
|
|
result0 = null;
|
|
pos = pos1;
|
|
}
|
|
} else {
|
|
result0 = null;
|
|
pos = pos1;
|
|
}
|
|
} else {
|
|
result0 = null;
|
|
pos = pos1;
|
|
}
|
|
} else {
|
|
result0 = null;
|
|
pos = pos1;
|
|
}
|
|
} else {
|
|
result0 = null;
|
|
pos = pos1;
|
|
}
|
|
} else {
|
|
result0 = null;
|
|
pos = pos1;
|
|
}
|
|
if (result0 !== null) {
|
|
result0 = (function(offset, inverted, parts, flags) {
|
|
var partsConverted = map(parts, function(part) { return part.data; });
|
|
var rawText = "["
|
|
+ inverted
|
|
+ map(parts, function(part) { return part.rawText; }).join("")
|
|
+ "]"
|
|
+ flags;
|
|
|
|
return {
|
|
type: "class",
|
|
inverted: inverted === "^",
|
|
ignoreCase: flags === "i",
|
|
parts: partsConverted,
|
|
// FIXME: Get the raw text from the input directly.
|
|
rawText: rawText
|
|
};
|
|
})(pos0, result0[1], result0[2], result0[4]);
|
|
}
|
|
if (result0 === null) {
|
|
pos = pos0;
|
|
}
|
|
reportFailures--;
|
|
if (reportFailures === 0 && result0 === null) {
|
|
matchFailed("character class");
|
|
}
|
|
return result0;
|
|
}
|
|
|
|
function parse_classCharacterRange() {
|
|
var result0, result1, result2;
|
|
var pos0, pos1;
|
|
|
|
pos0 = pos;
|
|
pos1 = pos;
|
|
result0 = parse_classCharacter();
|
|
if (result0 !== null) {
|
|
if (input.charCodeAt(pos) === 45) {
|
|
result1 = "-";
|
|
pos++;
|
|
} else {
|
|
result1 = null;
|
|
if (reportFailures === 0) {
|
|
matchFailed("\"-\"");
|
|
}
|
|
}
|
|
if (result1 !== null) {
|
|
result2 = parse_classCharacter();
|
|
if (result2 !== null) {
|
|
result0 = [result0, result1, result2];
|
|
} else {
|
|
result0 = null;
|
|
pos = pos1;
|
|
}
|
|
} else {
|
|
result0 = null;
|
|
pos = pos1;
|
|
}
|
|
} else {
|
|
result0 = null;
|
|
pos = pos1;
|
|
}
|
|
if (result0 !== null) {
|
|
result0 = (function(offset, begin, end) {
|
|
if (begin.data.charCodeAt(0) > end.data.charCodeAt(0)) {
|
|
throw new this.SyntaxError(
|
|
"Invalid character range: " + begin.rawText + "-" + end.rawText + "."
|
|
);
|
|
}
|
|
|
|
return {
|
|
data: [begin.data, end.data],
|
|
// FIXME: Get the raw text from the input directly.
|
|
rawText: begin.rawText + "-" + end.rawText
|
|
};
|
|
})(pos0, result0[0], result0[2]);
|
|
}
|
|
if (result0 === null) {
|
|
pos = pos0;
|
|
}
|
|
return result0;
|
|
}
|
|
|
|
function parse_classCharacter() {
|
|
var result0;
|
|
var pos0;
|
|
|
|
pos0 = pos;
|
|
result0 = parse_bracketDelimitedCharacter();
|
|
if (result0 !== null) {
|
|
result0 = (function(offset, char_) {
|
|
return {
|
|
data: char_,
|
|
// FIXME: Get the raw text from the input directly.
|
|
rawText: quoteForRegexpClass(char_)
|
|
};
|
|
})(pos0, result0);
|
|
}
|
|
if (result0 === null) {
|
|
pos = pos0;
|
|
}
|
|
return result0;
|
|
}
|
|
|
|
function parse_bracketDelimitedCharacter() {
|
|
var result0;
|
|
|
|
result0 = parse_simpleBracketDelimitedCharacter();
|
|
if (result0 === null) {
|
|
result0 = parse_simpleEscapeSequence();
|
|
if (result0 === null) {
|
|
result0 = parse_zeroEscapeSequence();
|
|
if (result0 === null) {
|
|
result0 = parse_hexEscapeSequence();
|
|
if (result0 === null) {
|
|
result0 = parse_unicodeEscapeSequence();
|
|
if (result0 === null) {
|
|
result0 = parse_eolEscapeSequence();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return result0;
|
|
}
|
|
|
|
function parse_simpleBracketDelimitedCharacter() {
|
|
var result0, result1;
|
|
var pos0, pos1, pos2;
|
|
|
|
pos0 = pos;
|
|
pos1 = pos;
|
|
pos2 = pos;
|
|
reportFailures++;
|
|
if (input.charCodeAt(pos) === 93) {
|
|
result0 = "]";
|
|
pos++;
|
|
} else {
|
|
result0 = null;
|
|
if (reportFailures === 0) {
|
|
matchFailed("\"]\"");
|
|
}
|
|
}
|
|
if (result0 === null) {
|
|
if (input.charCodeAt(pos) === 92) {
|
|
result0 = "\\";
|
|
pos++;
|
|
} else {
|
|
result0 = null;
|
|
if (reportFailures === 0) {
|
|
matchFailed("\"\\\\\"");
|
|
}
|
|
}
|
|
if (result0 === null) {
|
|
result0 = parse_eolChar();
|
|
}
|
|
}
|
|
reportFailures--;
|
|
if (result0 === null) {
|
|
result0 = "";
|
|
} else {
|
|
result0 = null;
|
|
pos = pos2;
|
|
}
|
|
if (result0 !== null) {
|
|
if (input.length > pos) {
|
|
result1 = input.charAt(pos);
|
|
pos++;
|
|
} else {
|
|
result1 = null;
|
|
if (reportFailures === 0) {
|
|
matchFailed("any character");
|
|
}
|
|
}
|
|
if (result1 !== null) {
|
|
result0 = [result0, result1];
|
|
} else {
|
|
result0 = null;
|
|
pos = pos1;
|
|
}
|
|
} else {
|
|
result0 = null;
|
|
pos = pos1;
|
|
}
|
|
if (result0 !== null) {
|
|
result0 = (function(offset, char_) { return char_; })(pos0, result0[1]);
|
|
}
|
|
if (result0 === null) {
|
|
pos = pos0;
|
|
}
|
|
return result0;
|
|
}
|
|
|
|
function parse_simpleEscapeSequence() {
|
|
var result0, result1, result2;
|
|
var pos0, pos1, pos2;
|
|
|
|
pos0 = pos;
|
|
pos1 = pos;
|
|
if (input.charCodeAt(pos) === 92) {
|
|
result0 = "\\";
|
|
pos++;
|
|
} else {
|
|
result0 = null;
|
|
if (reportFailures === 0) {
|
|
matchFailed("\"\\\\\"");
|
|
}
|
|
}
|
|
if (result0 !== null) {
|
|
pos2 = pos;
|
|
reportFailures++;
|
|
result1 = parse_digit();
|
|
if (result1 === null) {
|
|
if (input.charCodeAt(pos) === 120) {
|
|
result1 = "x";
|
|
pos++;
|
|
} else {
|
|
result1 = null;
|
|
if (reportFailures === 0) {
|
|
matchFailed("\"x\"");
|
|
}
|
|
}
|
|
if (result1 === null) {
|
|
if (input.charCodeAt(pos) === 117) {
|
|
result1 = "u";
|
|
pos++;
|
|
} else {
|
|
result1 = null;
|
|
if (reportFailures === 0) {
|
|
matchFailed("\"u\"");
|
|
}
|
|
}
|
|
if (result1 === null) {
|
|
result1 = parse_eolChar();
|
|
}
|
|
}
|
|
}
|
|
reportFailures--;
|
|
if (result1 === null) {
|
|
result1 = "";
|
|
} else {
|
|
result1 = null;
|
|
pos = pos2;
|
|
}
|
|
if (result1 !== null) {
|
|
if (input.length > pos) {
|
|
result2 = input.charAt(pos);
|
|
pos++;
|
|
} else {
|
|
result2 = null;
|
|
if (reportFailures === 0) {
|
|
matchFailed("any character");
|
|
}
|
|
}
|
|
if (result2 !== null) {
|
|
result0 = [result0, result1, result2];
|
|
} else {
|
|
result0 = null;
|
|
pos = pos1;
|
|
}
|
|
} else {
|
|
result0 = null;
|
|
pos = pos1;
|
|
}
|
|
} else {
|
|
result0 = null;
|
|
pos = pos1;
|
|
}
|
|
if (result0 !== null) {
|
|
result0 = (function(offset, char_) {
|
|
return char_
|
|
.replace("b", "\b")
|
|
.replace("f", "\f")
|
|
.replace("n", "\n")
|
|
.replace("r", "\r")
|
|
.replace("t", "\t")
|
|
.replace("v", "\x0B"); // IE does not recognize "\v".
|
|
})(pos0, result0[2]);
|
|
}
|
|
if (result0 === null) {
|
|
pos = pos0;
|
|
}
|
|
return result0;
|
|
}
|
|
|
|
function parse_zeroEscapeSequence() {
|
|
var result0, result1;
|
|
var pos0, pos1, pos2;
|
|
|
|
pos0 = pos;
|
|
pos1 = pos;
|
|
if (input.substr(pos, 2) === "\\0") {
|
|
result0 = "\\0";
|
|
pos += 2;
|
|
} else {
|
|
result0 = null;
|
|
if (reportFailures === 0) {
|
|
matchFailed("\"\\\\0\"");
|
|
}
|
|
}
|
|
if (result0 !== null) {
|
|
pos2 = pos;
|
|
reportFailures++;
|
|
result1 = parse_digit();
|
|
reportFailures--;
|
|
if (result1 === null) {
|
|
result1 = "";
|
|
} else {
|
|
result1 = null;
|
|
pos = pos2;
|
|
}
|
|
if (result1 !== null) {
|
|
result0 = [result0, result1];
|
|
} else {
|
|
result0 = null;
|
|
pos = pos1;
|
|
}
|
|
} else {
|
|
result0 = null;
|
|
pos = pos1;
|
|
}
|
|
if (result0 !== null) {
|
|
result0 = (function(offset) { return "\x00"; })(pos0);
|
|
}
|
|
if (result0 === null) {
|
|
pos = pos0;
|
|
}
|
|
return result0;
|
|
}
|
|
|
|
function parse_hexEscapeSequence() {
|
|
var result0, result1, result2;
|
|
var pos0, pos1;
|
|
|
|
pos0 = pos;
|
|
pos1 = pos;
|
|
if (input.substr(pos, 2) === "\\x") {
|
|
result0 = "\\x";
|
|
pos += 2;
|
|
} else {
|
|
result0 = null;
|
|
if (reportFailures === 0) {
|
|
matchFailed("\"\\\\x\"");
|
|
}
|
|
}
|
|
if (result0 !== null) {
|
|
result1 = parse_hexDigit();
|
|
if (result1 !== null) {
|
|
result2 = parse_hexDigit();
|
|
if (result2 !== null) {
|
|
result0 = [result0, result1, result2];
|
|
} else {
|
|
result0 = null;
|
|
pos = pos1;
|
|
}
|
|
} else {
|
|
result0 = null;
|
|
pos = pos1;
|
|
}
|
|
} else {
|
|
result0 = null;
|
|
pos = pos1;
|
|
}
|
|
if (result0 !== null) {
|
|
result0 = (function(offset, h1, h2) {
|
|
return String.fromCharCode(parseInt(h1 + h2, 16));
|
|
})(pos0, result0[1], result0[2]);
|
|
}
|
|
if (result0 === null) {
|
|
pos = pos0;
|
|
}
|
|
return result0;
|
|
}
|
|
|
|
function parse_unicodeEscapeSequence() {
|
|
var result0, result1, result2, result3, result4;
|
|
var pos0, pos1;
|
|
|
|
pos0 = pos;
|
|
pos1 = pos;
|
|
if (input.substr(pos, 2) === "\\u") {
|
|
result0 = "\\u";
|
|
pos += 2;
|
|
} else {
|
|
result0 = null;
|
|
if (reportFailures === 0) {
|
|
matchFailed("\"\\\\u\"");
|
|
}
|
|
}
|
|
if (result0 !== null) {
|
|
result1 = parse_hexDigit();
|
|
if (result1 !== null) {
|
|
result2 = parse_hexDigit();
|
|
if (result2 !== null) {
|
|
result3 = parse_hexDigit();
|
|
if (result3 !== null) {
|
|
result4 = parse_hexDigit();
|
|
if (result4 !== null) {
|
|
result0 = [result0, result1, result2, result3, result4];
|
|
} else {
|
|
result0 = null;
|
|
pos = pos1;
|
|
}
|
|
} else {
|
|
result0 = null;
|
|
pos = pos1;
|
|
}
|
|
} else {
|
|
result0 = null;
|
|
pos = pos1;
|
|
}
|
|
} else {
|
|
result0 = null;
|
|
pos = pos1;
|
|
}
|
|
} else {
|
|
result0 = null;
|
|
pos = pos1;
|
|
}
|
|
if (result0 !== null) {
|
|
result0 = (function(offset, h1, h2, h3, h4) {
|
|
return String.fromCharCode(parseInt(h1 + h2 + h3 + h4, 16));
|
|
})(pos0, result0[1], result0[2], result0[3], result0[4]);
|
|
}
|
|
if (result0 === null) {
|
|
pos = pos0;
|
|
}
|
|
return result0;
|
|
}
|
|
|
|
function parse_eolEscapeSequence() {
|
|
var result0, result1;
|
|
var pos0, pos1;
|
|
|
|
pos0 = pos;
|
|
pos1 = pos;
|
|
if (input.charCodeAt(pos) === 92) {
|
|
result0 = "\\";
|
|
pos++;
|
|
} else {
|
|
result0 = null;
|
|
if (reportFailures === 0) {
|
|
matchFailed("\"\\\\\"");
|
|
}
|
|
}
|
|
if (result0 !== null) {
|
|
result1 = parse_eol();
|
|
if (result1 !== null) {
|
|
result0 = [result0, result1];
|
|
} else {
|
|
result0 = null;
|
|
pos = pos1;
|
|
}
|
|
} else {
|
|
result0 = null;
|
|
pos = pos1;
|
|
}
|
|
if (result0 !== null) {
|
|
result0 = (function(offset, eol) { return eol; })(pos0, result0[1]);
|
|
}
|
|
if (result0 === null) {
|
|
pos = pos0;
|
|
}
|
|
return result0;
|
|
}
|
|
|
|
function parse_digit() {
|
|
var result0;
|
|
|
|
if (/^[0-9]/.test(input.charAt(pos))) {
|
|
result0 = input.charAt(pos);
|
|
pos++;
|
|
} else {
|
|
result0 = null;
|
|
if (reportFailures === 0) {
|
|
matchFailed("[0-9]");
|
|
}
|
|
}
|
|
return result0;
|
|
}
|
|
|
|
function parse_hexDigit() {
|
|
var result0;
|
|
|
|
if (/^[0-9a-fA-F]/.test(input.charAt(pos))) {
|
|
result0 = input.charAt(pos);
|
|
pos++;
|
|
} else {
|
|
result0 = null;
|
|
if (reportFailures === 0) {
|
|
matchFailed("[0-9a-fA-F]");
|
|
}
|
|
}
|
|
return result0;
|
|
}
|
|
|
|
function parse_letter() {
|
|
var result0;
|
|
|
|
result0 = parse_lowerCaseLetter();
|
|
if (result0 === null) {
|
|
result0 = parse_upperCaseLetter();
|
|
}
|
|
return result0;
|
|
}
|
|
|
|
function parse_lowerCaseLetter() {
|
|
var result0;
|
|
|
|
if (/^[a-z]/.test(input.charAt(pos))) {
|
|
result0 = input.charAt(pos);
|
|
pos++;
|
|
} else {
|
|
result0 = null;
|
|
if (reportFailures === 0) {
|
|
matchFailed("[a-z]");
|
|
}
|
|
}
|
|
return result0;
|
|
}
|
|
|
|
function parse_upperCaseLetter() {
|
|
var result0;
|
|
|
|
if (/^[A-Z]/.test(input.charAt(pos))) {
|
|
result0 = input.charAt(pos);
|
|
pos++;
|
|
} else {
|
|
result0 = null;
|
|
if (reportFailures === 0) {
|
|
matchFailed("[A-Z]");
|
|
}
|
|
}
|
|
return result0;
|
|
}
|
|
|
|
function parse___() {
|
|
var result0, result1;
|
|
|
|
result0 = [];
|
|
result1 = parse_whitespace();
|
|
if (result1 === null) {
|
|
result1 = parse_eol();
|
|
if (result1 === null) {
|
|
result1 = parse_comment();
|
|
}
|
|
}
|
|
while (result1 !== null) {
|
|
result0.push(result1);
|
|
result1 = parse_whitespace();
|
|
if (result1 === null) {
|
|
result1 = parse_eol();
|
|
if (result1 === null) {
|
|
result1 = parse_comment();
|
|
}
|
|
}
|
|
}
|
|
return result0;
|
|
}
|
|
|
|
function parse_comment() {
|
|
var result0;
|
|
|
|
reportFailures++;
|
|
result0 = parse_singleLineComment();
|
|
if (result0 === null) {
|
|
result0 = parse_multiLineComment();
|
|
}
|
|
reportFailures--;
|
|
if (reportFailures === 0 && result0 === null) {
|
|
matchFailed("comment");
|
|
}
|
|
return result0;
|
|
}
|
|
|
|
function parse_singleLineComment() {
|
|
var result0, result1, result2, result3;
|
|
var pos0, pos1, pos2;
|
|
|
|
pos0 = pos;
|
|
if (input.substr(pos, 2) === "//") {
|
|
result0 = "//";
|
|
pos += 2;
|
|
} else {
|
|
result0 = null;
|
|
if (reportFailures === 0) {
|
|
matchFailed("\"//\"");
|
|
}
|
|
}
|
|
if (result0 !== null) {
|
|
result1 = [];
|
|
pos1 = pos;
|
|
pos2 = pos;
|
|
reportFailures++;
|
|
result2 = parse_eolChar();
|
|
reportFailures--;
|
|
if (result2 === null) {
|
|
result2 = "";
|
|
} else {
|
|
result2 = null;
|
|
pos = pos2;
|
|
}
|
|
if (result2 !== null) {
|
|
if (input.length > pos) {
|
|
result3 = input.charAt(pos);
|
|
pos++;
|
|
} else {
|
|
result3 = null;
|
|
if (reportFailures === 0) {
|
|
matchFailed("any character");
|
|
}
|
|
}
|
|
if (result3 !== null) {
|
|
result2 = [result2, result3];
|
|
} else {
|
|
result2 = null;
|
|
pos = pos1;
|
|
}
|
|
} else {
|
|
result2 = null;
|
|
pos = pos1;
|
|
}
|
|
while (result2 !== null) {
|
|
result1.push(result2);
|
|
pos1 = pos;
|
|
pos2 = pos;
|
|
reportFailures++;
|
|
result2 = parse_eolChar();
|
|
reportFailures--;
|
|
if (result2 === null) {
|
|
result2 = "";
|
|
} else {
|
|
result2 = null;
|
|
pos = pos2;
|
|
}
|
|
if (result2 !== null) {
|
|
if (input.length > pos) {
|
|
result3 = input.charAt(pos);
|
|
pos++;
|
|
} else {
|
|
result3 = null;
|
|
if (reportFailures === 0) {
|
|
matchFailed("any character");
|
|
}
|
|
}
|
|
if (result3 !== null) {
|
|
result2 = [result2, result3];
|
|
} else {
|
|
result2 = null;
|
|
pos = pos1;
|
|
}
|
|
} else {
|
|
result2 = null;
|
|
pos = pos1;
|
|
}
|
|
}
|
|
if (result1 !== null) {
|
|
result0 = [result0, result1];
|
|
} else {
|
|
result0 = null;
|
|
pos = pos0;
|
|
}
|
|
} else {
|
|
result0 = null;
|
|
pos = pos0;
|
|
}
|
|
return result0;
|
|
}
|
|
|
|
function parse_multiLineComment() {
|
|
var result0, result1, result2, result3;
|
|
var pos0, pos1, pos2;
|
|
|
|
pos0 = pos;
|
|
if (input.substr(pos, 2) === "/*") {
|
|
result0 = "/*";
|
|
pos += 2;
|
|
} else {
|
|
result0 = null;
|
|
if (reportFailures === 0) {
|
|
matchFailed("\"/*\"");
|
|
}
|
|
}
|
|
if (result0 !== null) {
|
|
result1 = [];
|
|
pos1 = pos;
|
|
pos2 = pos;
|
|
reportFailures++;
|
|
if (input.substr(pos, 2) === "*/") {
|
|
result2 = "*/";
|
|
pos += 2;
|
|
} else {
|
|
result2 = null;
|
|
if (reportFailures === 0) {
|
|
matchFailed("\"*/\"");
|
|
}
|
|
}
|
|
reportFailures--;
|
|
if (result2 === null) {
|
|
result2 = "";
|
|
} else {
|
|
result2 = null;
|
|
pos = pos2;
|
|
}
|
|
if (result2 !== null) {
|
|
if (input.length > pos) {
|
|
result3 = input.charAt(pos);
|
|
pos++;
|
|
} else {
|
|
result3 = null;
|
|
if (reportFailures === 0) {
|
|
matchFailed("any character");
|
|
}
|
|
}
|
|
if (result3 !== null) {
|
|
result2 = [result2, result3];
|
|
} else {
|
|
result2 = null;
|
|
pos = pos1;
|
|
}
|
|
} else {
|
|
result2 = null;
|
|
pos = pos1;
|
|
}
|
|
while (result2 !== null) {
|
|
result1.push(result2);
|
|
pos1 = pos;
|
|
pos2 = pos;
|
|
reportFailures++;
|
|
if (input.substr(pos, 2) === "*/") {
|
|
result2 = "*/";
|
|
pos += 2;
|
|
} else {
|
|
result2 = null;
|
|
if (reportFailures === 0) {
|
|
matchFailed("\"*/\"");
|
|
}
|
|
}
|
|
reportFailures--;
|
|
if (result2 === null) {
|
|
result2 = "";
|
|
} else {
|
|
result2 = null;
|
|
pos = pos2;
|
|
}
|
|
if (result2 !== null) {
|
|
if (input.length > pos) {
|
|
result3 = input.charAt(pos);
|
|
pos++;
|
|
} else {
|
|
result3 = null;
|
|
if (reportFailures === 0) {
|
|
matchFailed("any character");
|
|
}
|
|
}
|
|
if (result3 !== null) {
|
|
result2 = [result2, result3];
|
|
} else {
|
|
result2 = null;
|
|
pos = pos1;
|
|
}
|
|
} else {
|
|
result2 = null;
|
|
pos = pos1;
|
|
}
|
|
}
|
|
if (result1 !== null) {
|
|
if (input.substr(pos, 2) === "*/") {
|
|
result2 = "*/";
|
|
pos += 2;
|
|
} else {
|
|
result2 = null;
|
|
if (reportFailures === 0) {
|
|
matchFailed("\"*/\"");
|
|
}
|
|
}
|
|
if (result2 !== null) {
|
|
result0 = [result0, result1, result2];
|
|
} else {
|
|
result0 = null;
|
|
pos = pos0;
|
|
}
|
|
} else {
|
|
result0 = null;
|
|
pos = pos0;
|
|
}
|
|
} else {
|
|
result0 = null;
|
|
pos = pos0;
|
|
}
|
|
return result0;
|
|
}
|
|
|
|
function parse_eol() {
|
|
var result0;
|
|
|
|
reportFailures++;
|
|
if (input.charCodeAt(pos) === 10) {
|
|
result0 = "\n";
|
|
pos++;
|
|
} else {
|
|
result0 = null;
|
|
if (reportFailures === 0) {
|
|
matchFailed("\"\\n\"");
|
|
}
|
|
}
|
|
if (result0 === null) {
|
|
if (input.substr(pos, 2) === "\r\n") {
|
|
result0 = "\r\n";
|
|
pos += 2;
|
|
} else {
|
|
result0 = null;
|
|
if (reportFailures === 0) {
|
|
matchFailed("\"\\r\\n\"");
|
|
}
|
|
}
|
|
if (result0 === null) {
|
|
if (input.charCodeAt(pos) === 13) {
|
|
result0 = "\r";
|
|
pos++;
|
|
} else {
|
|
result0 = null;
|
|
if (reportFailures === 0) {
|
|
matchFailed("\"\\r\"");
|
|
}
|
|
}
|
|
if (result0 === null) {
|
|
if (input.charCodeAt(pos) === 8232) {
|
|
result0 = "\u2028";
|
|
pos++;
|
|
} else {
|
|
result0 = null;
|
|
if (reportFailures === 0) {
|
|
matchFailed("\"\\u2028\"");
|
|
}
|
|
}
|
|
if (result0 === null) {
|
|
if (input.charCodeAt(pos) === 8233) {
|
|
result0 = "\u2029";
|
|
pos++;
|
|
} else {
|
|
result0 = null;
|
|
if (reportFailures === 0) {
|
|
matchFailed("\"\\u2029\"");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
reportFailures--;
|
|
if (reportFailures === 0 && result0 === null) {
|
|
matchFailed("end of line");
|
|
}
|
|
return result0;
|
|
}
|
|
|
|
function parse_eolChar() {
|
|
var result0;
|
|
|
|
if (/^[\n\r\u2028\u2029]/.test(input.charAt(pos))) {
|
|
result0 = input.charAt(pos);
|
|
pos++;
|
|
} else {
|
|
result0 = null;
|
|
if (reportFailures === 0) {
|
|
matchFailed("[\\n\\r\\u2028\\u2029]");
|
|
}
|
|
}
|
|
return result0;
|
|
}
|
|
|
|
function parse_whitespace() {
|
|
var result0;
|
|
|
|
reportFailures++;
|
|
if (/^[ \t\x0B\f\xA0\uFEFF\u1680\u180E\u2000-\u200A\u202F\u205F\u3000]/.test(input.charAt(pos))) {
|
|
result0 = input.charAt(pos);
|
|
pos++;
|
|
} else {
|
|
result0 = null;
|
|
if (reportFailures === 0) {
|
|
matchFailed("[ \\t\\x0B\\f\\xA0\\uFEFF\\u1680\\u180E\\u2000-\\u200A\\u202F\\u205F\\u3000]");
|
|
}
|
|
}
|
|
reportFailures--;
|
|
if (reportFailures === 0 && result0 === null) {
|
|
matchFailed("whitespace");
|
|
}
|
|
return result0;
|
|
}
|
|
|
|
|
|
function cleanupExpected(expected) {
|
|
expected.sort();
|
|
|
|
var lastExpected = null;
|
|
var cleanExpected = [];
|
|
for (var i = 0; i < expected.length; i++) {
|
|
if (expected[i] !== lastExpected) {
|
|
cleanExpected.push(expected[i]);
|
|
lastExpected = expected[i];
|
|
}
|
|
}
|
|
return cleanExpected;
|
|
}
|
|
|
|
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 line = 1;
|
|
var column = 1;
|
|
var seenCR = false;
|
|
|
|
for (var i = 0; i < Math.max(pos, rightmostFailuresPos); 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 };
|
|
}
|
|
|
|
|
|
var result = parseFunctions[startRule]();
|
|
|
|
/*
|
|
* The parser is now in one of the following three states:
|
|
*
|
|
* 1. The parser successfully parsed the whole input.
|
|
*
|
|
* - |result !== null|
|
|
* - |pos === input.length|
|
|
* - |rightmostFailuresExpected| may or may not contain something
|
|
*
|
|
* 2. The parser successfully parsed only a part of the input.
|
|
*
|
|
* - |result !== null|
|
|
* - |pos < input.length|
|
|
* - |rightmostFailuresExpected| may or may not contain something
|
|
*
|
|
* 3. The parser did not successfully parse any part of the input.
|
|
*
|
|
* - |result === null|
|
|
* - |pos === 0|
|
|
* - |rightmostFailuresExpected| contains at least one failure
|
|
*
|
|
* All code following this comment (including called functions) must
|
|
* handle these states.
|
|
*/
|
|
if (result === null || pos !== input.length) {
|
|
var offset = Math.max(pos, rightmostFailuresPos);
|
|
var found = offset < input.length ? input.charAt(offset) : null;
|
|
var errorPosition = computeErrorPosition();
|
|
|
|
throw new this.SyntaxError(
|
|
cleanupExpected(rightmostFailuresExpected),
|
|
found,
|
|
offset,
|
|
errorPosition.line,
|
|
errorPosition.column
|
|
);
|
|
}
|
|
|
|
return result;
|
|
},
|
|
|
|
/* Returns the parser source code. */
|
|
toSource: function() { return this._source; }
|
|
};
|
|
|
|
/* Thrown when a parser encounters a syntax error. */
|
|
|
|
result.SyntaxError = function(expected, found, offset, line, column) {
|
|
function buildMessage(expected, found) {
|
|
var expectedHumanized, foundHumanized;
|
|
|
|
switch (expected.length) {
|
|
case 0:
|
|
expectedHumanized = "end of input";
|
|
break;
|
|
case 1:
|
|
expectedHumanized = expected[0];
|
|
break;
|
|
default:
|
|
expectedHumanized = expected.slice(0, expected.length - 1).join(", ")
|
|
+ " or "
|
|
+ expected[expected.length - 1];
|
|
}
|
|
|
|
foundHumanized = found ? quote(found) : "end of input";
|
|
|
|
return "Expected " + expectedHumanized + " but " + foundHumanized + " found.";
|
|
}
|
|
|
|
this.name = "SyntaxError";
|
|
this.expected = expected;
|
|
this.found = found;
|
|
this.message = buildMessage(expected, found);
|
|
this.offset = offset;
|
|
this.line = line;
|
|
this.column = column;
|
|
};
|
|
|
|
result.SyntaxError.prototype = Error.prototype;
|
|
|
|
return result;
|
|
})();
|
|
PEG.compiler = {
|
|
/*
|
|
* Names of passes that will get run during the compilation (in the specified
|
|
* order).
|
|
*/
|
|
appliedPassNames: [
|
|
"reportMissingRules",
|
|
"reportLeftRecursion",
|
|
"removeProxyRules",
|
|
"computeVarNames",
|
|
"computeParams"
|
|
],
|
|
|
|
/*
|
|
* Generates a parser from a specified grammar AST. Throws |PEG.GrammarError|
|
|
* if the AST contains a semantic error. Note that not all errors are detected
|
|
* during the generation and some may protrude to the generated parser and
|
|
* cause its malfunction.
|
|
*/
|
|
compile: function(ast, options) {
|
|
var that = this;
|
|
|
|
each(this.appliedPassNames, function(passName) {
|
|
that.passes[passName](ast);
|
|
});
|
|
|
|
var source = this.emitter(ast, options);
|
|
var result = eval(source);
|
|
result._source = source;
|
|
|
|
return result;
|
|
}
|
|
};
|
|
|
|
/*
|
|
* Compiler passes.
|
|
*
|
|
* Each pass is a function that is passed the AST. It can perform checks on it
|
|
* or modify it as needed. If the pass encounters a semantic error, it throws
|
|
* |PEG.GrammarError|.
|
|
*/
|
|
PEG.compiler.passes = {
|
|
/* Checks that all referenced rules exist. */
|
|
reportMissingRules: function(ast) {
|
|
function nop() {}
|
|
|
|
function checkExpression(node) { check(node.expression); }
|
|
|
|
function checkSubnodes(propertyName) {
|
|
return function(node) { each(node[propertyName], check); };
|
|
}
|
|
|
|
var check = buildNodeVisitor({
|
|
grammar: checkSubnodes("rules"),
|
|
rule: checkExpression,
|
|
choice: checkSubnodes("alternatives"),
|
|
sequence: checkSubnodes("elements"),
|
|
labeled: checkExpression,
|
|
simple_and: checkExpression,
|
|
simple_not: checkExpression,
|
|
semantic_and: nop,
|
|
semantic_not: nop,
|
|
optional: checkExpression,
|
|
zero_or_more: checkExpression,
|
|
one_or_more: checkExpression,
|
|
action: checkExpression,
|
|
|
|
rule_ref:
|
|
function(node) {
|
|
if (!findRuleByName(ast, node.name)) {
|
|
throw new PEG.GrammarError(
|
|
"Referenced rule \"" + node.name + "\" does not exist."
|
|
);
|
|
}
|
|
},
|
|
|
|
literal: nop,
|
|
any: nop,
|
|
"class": nop
|
|
});
|
|
|
|
check(ast);
|
|
},
|
|
|
|
/* Checks that no left recursion is present. */
|
|
reportLeftRecursion: function(ast) {
|
|
function nop() {}
|
|
|
|
function checkExpression(node, appliedRules) {
|
|
check(node.expression, appliedRules);
|
|
}
|
|
|
|
function checkSubnodes(propertyName) {
|
|
return function(node, appliedRules) {
|
|
each(node[propertyName], function(subnode) {
|
|
check(subnode, appliedRules);
|
|
});
|
|
};
|
|
}
|
|
|
|
var check = buildNodeVisitor({
|
|
grammar: checkSubnodes("rules"),
|
|
|
|
rule:
|
|
function(node, appliedRules) {
|
|
check(node.expression, appliedRules.concat(node.name));
|
|
},
|
|
|
|
choice: checkSubnodes("alternatives"),
|
|
|
|
sequence:
|
|
function(node, appliedRules) {
|
|
if (node.elements.length > 0) {
|
|
check(node.elements[0], appliedRules);
|
|
}
|
|
},
|
|
|
|
labeled: checkExpression,
|
|
simple_and: checkExpression,
|
|
simple_not: checkExpression,
|
|
semantic_and: nop,
|
|
semantic_not: nop,
|
|
optional: checkExpression,
|
|
zero_or_more: checkExpression,
|
|
one_or_more: checkExpression,
|
|
action: checkExpression,
|
|
|
|
rule_ref:
|
|
function(node, appliedRules) {
|
|
if (contains(appliedRules, node.name)) {
|
|
throw new PEG.GrammarError(
|
|
"Left recursion detected for rule \"" + node.name + "\"."
|
|
);
|
|
}
|
|
check(findRuleByName(ast, node.name), appliedRules);
|
|
},
|
|
|
|
literal: nop,
|
|
any: nop,
|
|
"class": nop
|
|
});
|
|
|
|
check(ast, []);
|
|
},
|
|
|
|
/*
|
|
* Removes proxy rules -- that is, rules that only delegate to other rule.
|
|
*/
|
|
removeProxyRules: function(ast) {
|
|
function isProxyRule(node) {
|
|
return node.type === "rule" && node.expression.type === "rule_ref";
|
|
}
|
|
|
|
function replaceRuleRefs(ast, from, to) {
|
|
function nop() {}
|
|
|
|
function replaceInExpression(node, from, to) {
|
|
replace(node.expression, from, to);
|
|
}
|
|
|
|
function replaceInSubnodes(propertyName) {
|
|
return function(node, from, to) {
|
|
each(node[propertyName], function(subnode) {
|
|
replace(subnode, from, to);
|
|
});
|
|
};
|
|
}
|
|
|
|
var replace = buildNodeVisitor({
|
|
grammar: replaceInSubnodes("rules"),
|
|
rule: replaceInExpression,
|
|
choice: replaceInSubnodes("alternatives"),
|
|
sequence: replaceInSubnodes("elements"),
|
|
labeled: replaceInExpression,
|
|
simple_and: replaceInExpression,
|
|
simple_not: replaceInExpression,
|
|
semantic_and: nop,
|
|
semantic_not: nop,
|
|
optional: replaceInExpression,
|
|
zero_or_more: replaceInExpression,
|
|
one_or_more: replaceInExpression,
|
|
action: replaceInExpression,
|
|
|
|
rule_ref:
|
|
function(node, from, to) {
|
|
if (node.name === from) {
|
|
node.name = to;
|
|
}
|
|
},
|
|
|
|
literal: nop,
|
|
any: nop,
|
|
"class": nop
|
|
});
|
|
|
|
replace(ast, from, to);
|
|
}
|
|
|
|
var indices = [];
|
|
|
|
each(ast.rules, function(rule, i) {
|
|
if (isProxyRule(rule)) {
|
|
replaceRuleRefs(ast, rule.name, rule.expression.name);
|
|
if (rule.name === ast.startRule) {
|
|
ast.startRule = rule.expression.name;
|
|
}
|
|
indices.push(i);
|
|
}
|
|
});
|
|
|
|
indices.reverse();
|
|
|
|
each(indices, function(index) {
|
|
ast.rules.splice(index, 1);
|
|
});
|
|
},
|
|
|
|
/*
|
|
* Computes names of variables used for storing match results and parse
|
|
* positions in generated code. These variables are organized as two stacks.
|
|
* The following will hold after running this pass:
|
|
*
|
|
* * All nodes except "grammar" and "rule" nodes will have a |resultVar|
|
|
* property. It will contain a name of the variable that will store a
|
|
* match result of the expression represented by the node in generated
|
|
* code.
|
|
*
|
|
* * Some nodes will have a |posVar| property. It will contain a name of the
|
|
* variable that will store a parse position in generated code.
|
|
*
|
|
* * All "rule" nodes will contain |resultVars| and |posVars| properties.
|
|
* They will contain a list of values of |resultVar| and |posVar|
|
|
* properties used in rule's subnodes. (This is useful to declare
|
|
* variables in generated code.)
|
|
*/
|
|
computeVarNames: function(ast) {
|
|
function resultVar(index) { return "result" + index; }
|
|
function posVar(index) { return "pos" + index; }
|
|
|
|
function computeLeaf(node, index) {
|
|
node.resultVar = resultVar(index.result);
|
|
|
|
return { result: 0, pos: 0 };
|
|
}
|
|
|
|
function computeFromExpression(delta) {
|
|
return function(node, index) {
|
|
var depth = compute(
|
|
node.expression,
|
|
{
|
|
result: index.result + delta.result,
|
|
pos: index.pos + delta.pos
|
|
}
|
|
);
|
|
|
|
node.resultVar = resultVar(index.result);
|
|
if (delta.pos !== 0) {
|
|
node.posVar = posVar(index.pos);
|
|
}
|
|
|
|
return {
|
|
result: depth.result + delta.result,
|
|
pos: depth.pos + delta.pos
|
|
};
|
|
};
|
|
}
|
|
|
|
var compute = buildNodeVisitor({
|
|
grammar:
|
|
function(node, index) {
|
|
each(node.rules, function(node) {
|
|
compute(node, index);
|
|
});
|
|
},
|
|
|
|
rule:
|
|
function(node, index) {
|
|
var depth = compute(node.expression, index);
|
|
|
|
node.resultVar = resultVar(index.result);
|
|
node.resultVars = map(range(depth.result + 1), resultVar);
|
|
node.posVars = map(range(depth.pos), posVar);
|
|
},
|
|
|
|
choice:
|
|
function(node, index) {
|
|
var depths = map(node.alternatives, function(alternative) {
|
|
return compute(alternative, index);
|
|
});
|
|
|
|
node.resultVar = resultVar(index.result);
|
|
|
|
return {
|
|
result: Math.max.apply(null, pluck(depths, "result")),
|
|
pos: Math.max.apply(null, pluck(depths, "pos"))
|
|
};
|
|
},
|
|
|
|
sequence:
|
|
function(node, index) {
|
|
var depths = map(node.elements, function(element, i) {
|
|
return compute(
|
|
element,
|
|
{ result: index.result + i, pos: index.pos + 1 }
|
|
);
|
|
});
|
|
|
|
node.resultVar = resultVar(index.result);
|
|
node.posVar = posVar(index.pos);
|
|
|
|
return {
|
|
result:
|
|
node.elements.length > 0
|
|
? Math.max.apply(
|
|
null,
|
|
map(depths, function(d, i) { return i + d.result; })
|
|
)
|
|
: 0,
|
|
|
|
pos:
|
|
node.elements.length > 0
|
|
? 1 + Math.max.apply(null, pluck(depths, "pos"))
|
|
: 1
|
|
};
|
|
},
|
|
|
|
labeled: computeFromExpression({ result: 0, pos: 0 }),
|
|
simple_and: computeFromExpression({ result: 0, pos: 1 }),
|
|
simple_not: computeFromExpression({ result: 0, pos: 1 }),
|
|
semantic_and: computeLeaf,
|
|
semantic_not: computeLeaf,
|
|
optional: computeFromExpression({ result: 0, pos: 0 }),
|
|
zero_or_more: computeFromExpression({ result: 1, pos: 0 }),
|
|
one_or_more: computeFromExpression({ result: 1, pos: 0 }),
|
|
action: computeFromExpression({ result: 0, pos: 1 }),
|
|
rule_ref: computeLeaf,
|
|
literal: computeLeaf,
|
|
any: computeLeaf,
|
|
"class": computeLeaf
|
|
});
|
|
|
|
compute(ast, { result: 0, pos: 0 });
|
|
},
|
|
|
|
/*
|
|
* This pass walks through the AST and tracks what labels are visible at each
|
|
* point. For "action", "semantic_and" and "semantic_or" nodes it computes
|
|
* parameter names and values for the function used in generated code. (In the
|
|
* emitter, user's code is wrapped into a function that is immediately
|
|
* executed. Its parameter names correspond to visible labels and its
|
|
* parameter values to their captured values). Implicitly, this pass defines
|
|
* scoping rules for labels.
|
|
*
|
|
* After running this pass, all "action", "semantic_and" and "semantic_or"
|
|
* nodes will have a |params| property containing an object mapping parameter
|
|
* names to the expressions that will be used as their values.
|
|
*/
|
|
computeParams: function(ast) {
|
|
var envs = [];
|
|
|
|
function scoped(f) {
|
|
envs.push({});
|
|
f();
|
|
envs.pop();
|
|
}
|
|
|
|
function nop() {}
|
|
|
|
function computeForScopedExpression(node) {
|
|
scoped(function() { compute(node.expression); });
|
|
}
|
|
|
|
function computeParams(node) {
|
|
var env = envs[envs.length - 1], params = {}, name;
|
|
|
|
for (name in env) {
|
|
params[name] = env[name];
|
|
}
|
|
node.params = params;
|
|
}
|
|
|
|
var compute = buildNodeVisitor({
|
|
grammar:
|
|
function(node) {
|
|
each(node.rules, compute);
|
|
},
|
|
|
|
rule: computeForScopedExpression,
|
|
|
|
choice:
|
|
function(node) {
|
|
scoped(function() { each(node.alternatives, compute); });
|
|
},
|
|
|
|
sequence:
|
|
function(node) {
|
|
var env = envs[envs.length - 1], name;
|
|
|
|
function fixup(name) {
|
|
each(pluck(node.elements, "resultVar"), function(resultVar, i) {
|
|
if ((new RegExp("^" + resultVar + "(\\[\\d+\\])*$")).test(env[name])) {
|
|
env[name] = node.resultVar + "[" + i + "]"
|
|
+ env[name].substr(resultVar.length);
|
|
}
|
|
});
|
|
}
|
|
|
|
each(node.elements, compute);
|
|
|
|
for (name in env) {
|
|
fixup(name);
|
|
}
|
|
},
|
|
|
|
labeled:
|
|
function(node) {
|
|
envs[envs.length - 1][node.label] = node.resultVar;
|
|
|
|
scoped(function() { compute(node.expression); });
|
|
},
|
|
|
|
simple_and: computeForScopedExpression,
|
|
simple_not: computeForScopedExpression,
|
|
semantic_and: computeParams,
|
|
semantic_not: computeParams,
|
|
optional: computeForScopedExpression,
|
|
zero_or_more: computeForScopedExpression,
|
|
one_or_more: computeForScopedExpression,
|
|
|
|
action:
|
|
function(node) {
|
|
scoped(function() {
|
|
compute(node.expression);
|
|
computeParams(node);
|
|
});
|
|
},
|
|
|
|
rule_ref: nop,
|
|
literal: nop,
|
|
any: nop,
|
|
"class": nop
|
|
});
|
|
|
|
compute(ast);
|
|
}
|
|
};
|
|
/* Emits the generated code for the AST. */
|
|
PEG.compiler.emitter = function(ast, options) {
|
|
options = options || {};
|
|
if (options.cache === undefined) {
|
|
options.cache = false;
|
|
}
|
|
if (options.trackLineAndColumn === undefined) {
|
|
options.trackLineAndColumn = false;
|
|
}
|
|
|
|
/*
|
|
* Codie 1.1.0
|
|
*
|
|
* https://github.com/dmajda/codie
|
|
*
|
|
* Copyright (c) 2011-2012 David Majda
|
|
* Licensend under the MIT license.
|
|
*/
|
|
var Codie = (function(undefined) {
|
|
|
|
function stringEscape(s) {
|
|
function hex(ch) { return ch.charCodeAt(0).toString(16).toUpperCase(); }
|
|
|
|
/*
|
|
* 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.
|
|
*
|
|
* For portability, we also escape escape all control and non-ASCII
|
|
* characters. Note that "\0" and "\v" escape sequences are not used
|
|
* because JSHint does not like the first and IE the second.
|
|
*/
|
|
return s
|
|
.replace(/\\/g, '\\\\') // backslash
|
|
.replace(/"/g, '\\"') // closing double quote
|
|
.replace(/\x08/g, '\\b') // backspace
|
|
.replace(/\t/g, '\\t') // horizontal tab
|
|
.replace(/\n/g, '\\n') // line feed
|
|
.replace(/\f/g, '\\f') // form feed
|
|
.replace(/\r/g, '\\r') // carriage return
|
|
.replace(/[\x00-\x07\x0B\x0E\x0F]/g, function(ch) { return '\\x0' + hex(ch); })
|
|
.replace(/[\x10-\x1F\x80-\xFF]/g, function(ch) { return '\\x' + hex(ch); })
|
|
.replace(/[\u0180-\u0FFF]/g, function(ch) { return '\\u0' + hex(ch); })
|
|
.replace(/[\u1080-\uFFFF]/g, function(ch) { return '\\u' + hex(ch); });
|
|
}
|
|
|
|
function push(s) { return '__p.push(' + s + ');'; }
|
|
|
|
function pushRaw(template, length, state) {
|
|
function unindent(code, level, unindentFirst) {
|
|
return code.replace(
|
|
new RegExp('^.{' + level +'}', "gm"),
|
|
function(str, offset) {
|
|
if (offset === 0) {
|
|
return unindentFirst ? '' : str;
|
|
} else {
|
|
return "";
|
|
}
|
|
}
|
|
);
|
|
}
|
|
|
|
var escaped = stringEscape(unindent(
|
|
template.substring(0, length),
|
|
state.indentLevel(),
|
|
state.atBOL
|
|
));
|
|
|
|
return escaped.length > 0 ? push('"' + escaped + '"') : '';
|
|
}
|
|
|
|
|
|
var Codie = {
|
|
/* Codie version (uses semantic versioning). */
|
|
VERSION: "1.1.0",
|
|
|
|
/*
|
|
* Specifies by how many characters do #if/#else and #for unindent their
|
|
* content in the generated code.
|
|
*/
|
|
indentStep: 2,
|
|
|
|
/* Description of #-commands. Extend to define your own commands. */
|
|
commands: {
|
|
"if": {
|
|
params: /^(.*)$/,
|
|
compile: function(state, prefix, params) {
|
|
return ['if(' + params[0] + '){', []];
|
|
},
|
|
stackOp: "push"
|
|
},
|
|
"else": {
|
|
params: /^$/,
|
|
compile: function(state) {
|
|
var stack = state.commandStack,
|
|
insideElse = stack[stack.length - 1] === "else",
|
|
insideIf = stack[stack.length - 1] === "if";
|
|
|
|
if (insideElse) { throw new Error("Multiple #elses."); }
|
|
if (!insideIf) { throw new Error("Using #else outside of #if."); }
|
|
|
|
return ['}else{', []];
|
|
},
|
|
stackOp: "replace"
|
|
},
|
|
"for": {
|
|
params: /^([a-zA-Z_][a-zA-Z0-9_]*)[ \t]+in[ \t]+(.*)$/,
|
|
init: function(state) {
|
|
state.forCurrLevel = 0; // current level of #for loop nesting
|
|
state.forMaxLevel = 0; // maximum level of #for loop nesting
|
|
},
|
|
compile: function(state, prefix, params) {
|
|
var c = '__c' + state.forCurrLevel, // __c for "collection"
|
|
l = '__l' + state.forCurrLevel, // __l for "length"
|
|
i = '__i' + state.forCurrLevel; // __i for "index"
|
|
|
|
state.forCurrLevel++;
|
|
if (state.forMaxLevel < state.forCurrLevel) {
|
|
state.forMaxLevel = state.forCurrLevel;
|
|
}
|
|
|
|
return [
|
|
c + '=' + params[1] + ';'
|
|
+ l + '=' + c + '.length;'
|
|
+ 'for(' + i + '=0;' + i + '<' + l + ';' + i + '++){'
|
|
+ params[0] + '=' + c + '[' + i + '];',
|
|
[params[0], c, l, i]
|
|
];
|
|
},
|
|
exit: function(state) { state.forCurrLevel--; },
|
|
stackOp: "push"
|
|
},
|
|
"end": {
|
|
params: /^$/,
|
|
compile: function(state) {
|
|
var stack = state.commandStack, exit;
|
|
|
|
if (stack.length === 0) { throw new Error("Too many #ends."); }
|
|
|
|
exit = Codie.commands[stack[stack.length - 1]].exit;
|
|
if (exit) { exit(state); }
|
|
|
|
return ['}', []];
|
|
},
|
|
stackOp: "pop"
|
|
},
|
|
"block": {
|
|
params: /^(.*)$/,
|
|
compile: function(state, prefix, params) {
|
|
var x = '__x', // __x for "prefix",
|
|
n = '__n', // __n for "lines"
|
|
l = '__l', // __l for "length"
|
|
i = '__i'; // __i for "index"
|
|
|
|
/*
|
|
* Originally, the generated code used |String.prototype.replace|, but
|
|
* it is buggy in certain versions of V8 so it was rewritten. See the
|
|
* tests for details.
|
|
*/
|
|
return [
|
|
x + '="' + stringEscape(prefix.substring(state.indentLevel())) + '";'
|
|
+ n + '=(' + params[0] + ').toString().split("\\n");'
|
|
+ l + '=' + n + '.length;'
|
|
+ 'for(' + i + '=0;' + i + '<' + l + ';' + i + '++){'
|
|
+ n + '[' + i +']=' + x + '+' + n + '[' + i + ']+"\\n";'
|
|
+ '}'
|
|
+ push(n + '.join("")'),
|
|
[x, n, l, i]
|
|
];
|
|
},
|
|
stackOp: "nop"
|
|
}
|
|
},
|
|
|
|
/*
|
|
* Compiles a template into a function. When called, this function will
|
|
* execute the template in the context of an object passed in a parameter and
|
|
* return the result.
|
|
*/
|
|
template: function(template) {
|
|
var stackOps = {
|
|
push: function(stack, name) { stack.push(name); },
|
|
replace: function(stack, name) { stack[stack.length - 1] = name; },
|
|
pop: function(stack) { stack.pop(); },
|
|
nop: function() { }
|
|
};
|
|
|
|
function compileExpr(state, expr) {
|
|
state.atBOL = false;
|
|
return [push(expr), []];
|
|
}
|
|
|
|
function compileCommand(state, prefix, name, params) {
|
|
var command, match, result;
|
|
|
|
command = Codie.commands[name];
|
|
if (!command) { throw new Error("Unknown command: #" + name + "."); }
|
|
|
|
match = command.params.exec(params);
|
|
if (match === null) {
|
|
throw new Error(
|
|
"Invalid params for command #" + name + ": " + params + "."
|
|
);
|
|
}
|
|
|
|
result = command.compile(state, prefix, match.slice(1));
|
|
stackOps[command.stackOp](state.commandStack, name);
|
|
state.atBOL = true;
|
|
return result;
|
|
}
|
|
|
|
var state = { // compilation state
|
|
commandStack: [], // stack of commands as they were nested
|
|
atBOL: true, // is the next character to process at BOL?
|
|
indentLevel: function() {
|
|
return Codie.indentStep * this.commandStack.length;
|
|
}
|
|
},
|
|
code = '', // generated template function code
|
|
vars = ['__p=[]'], // variables used by generated code
|
|
name, match, result, i;
|
|
|
|
/* Initialize state. */
|
|
for (name in Codie.commands) {
|
|
if (Codie.commands[name].init) { Codie.commands[name].init(state); }
|
|
}
|
|
|
|
/* Compile the template. */
|
|
while ((match = /^([ \t]*)#([a-zA-Z_][a-zA-Z0-9_]*)(?:[ \t]+([^ \t\n][^\n]*))?[ \t]*(?:\n|$)|#\{([^}]*)\}/m.exec(template)) !== null) {
|
|
code += pushRaw(template, match.index, state);
|
|
result = match[2] !== undefined && match[2] !== ""
|
|
? compileCommand(state, match[1], match[2], match[3] || "") // #-command
|
|
: compileExpr(state, match[4]); // #{...}
|
|
code += result[0];
|
|
vars = vars.concat(result[1]);
|
|
template = template.substring(match.index + match[0].length);
|
|
}
|
|
code += pushRaw(template, template.length, state);
|
|
|
|
/* Check the final state. */
|
|
if (state.commandStack.length > 0) { throw new Error("Missing #end."); }
|
|
|
|
/* Sanitize the list of variables used by commands. */
|
|
vars.sort();
|
|
for (i = 0; i < vars.length; i++) {
|
|
if (vars[i] === vars[i - 1]) { vars.splice(i--, 1); }
|
|
}
|
|
|
|
/* Create the resulting function. */
|
|
return new Function("__v", [
|
|
'__v=__v||{};',
|
|
'var ' + vars.join(',') + ';',
|
|
'with(__v){',
|
|
code,
|
|
'return __p.join("").replace(/^\\n+|\\n+$/g,"");};'
|
|
].join(''));
|
|
}
|
|
};
|
|
|
|
return Codie;
|
|
|
|
})();
|
|
|
|
var templates = (function() {
|
|
var name,
|
|
templates = {},
|
|
sources = {
|
|
grammar: [
|
|
'(function(){',
|
|
' /*',
|
|
' * Generated by PEG.js 0.7.0.',
|
|
' *',
|
|
' * http://pegjs.majda.cz/',
|
|
' */',
|
|
' ',
|
|
/* This needs to be in sync with |quote| in utils.js. */
|
|
' function quote(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.',
|
|
' *',
|
|
' * For portability, we also escape escape all control and non-ASCII',
|
|
' * characters. Note that "\\0" and "\\v" escape sequences are not used',
|
|
' * because JSHint does not like the first and IE the second.',
|
|
' */',
|
|
' return \'"\' + s',
|
|
' .replace(/\\\\/g, \'\\\\\\\\\') // backslash',
|
|
' .replace(/"/g, \'\\\\"\') // closing quote character',
|
|
' .replace(/\\x08/g, \'\\\\b\') // backspace',
|
|
' .replace(/\\t/g, \'\\\\t\') // horizontal tab',
|
|
' .replace(/\\n/g, \'\\\\n\') // line feed',
|
|
' .replace(/\\f/g, \'\\\\f\') // form feed',
|
|
' .replace(/\\r/g, \'\\\\r\') // carriage return',
|
|
' .replace(/[\\x00-\\x07\\x0B\\x0E-\\x1F\\x80-\\uFFFF]/g, escape)',
|
|
' + \'"\';',
|
|
' }',
|
|
' ',
|
|
' var result = {',
|
|
' /*',
|
|
' * 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, startRule) {',
|
|
' var parseFunctions = {',
|
|
' #for rule in node.rules',
|
|
' #{string(rule.name) + ": parse_" + rule.name + (rule !== node.rules[node.rules.length - 1] ? "," : "")}',
|
|
' #end',
|
|
' };',
|
|
' ',
|
|
' if (startRule !== undefined) {',
|
|
' if (parseFunctions[startRule] === undefined) {',
|
|
' throw new Error("Invalid rule name: " + quote(startRule) + ".");',
|
|
' }',
|
|
' } else {',
|
|
' startRule = #{string(node.startRule)};',
|
|
' }',
|
|
' ',
|
|
' #{posInit("pos")};',
|
|
' var reportFailures = 0;', // 0 = report, anything > 0 = do not report
|
|
' #{posInit("rightmostFailuresPos")};',
|
|
' var rightmostFailuresExpected = [];',
|
|
' #if options.cache',
|
|
' var cache = {};',
|
|
' #end',
|
|
' ',
|
|
/* This needs to be in sync with |padLeft| in utils.js. */
|
|
' function padLeft(input, padding, length) {',
|
|
' var result = input;',
|
|
' ',
|
|
' var padLength = length - input.length;',
|
|
' for (var i = 0; i < padLength; i++) {',
|
|
' result = padding + result;',
|
|
' }',
|
|
' ',
|
|
' return result;',
|
|
' }',
|
|
' ',
|
|
/* This needs to be in sync with |escape| in utils.js. */
|
|
' function escape(ch) {',
|
|
' var charCode = ch.charCodeAt(0);',
|
|
' var escapeChar;',
|
|
' var length;',
|
|
' ',
|
|
' if (charCode <= 0xFF) {',
|
|
' escapeChar = \'x\';',
|
|
' length = 2;',
|
|
' } else {',
|
|
' escapeChar = \'u\';',
|
|
' length = 4;',
|
|
' }',
|
|
' ',
|
|
' return \'\\\\\' + escapeChar + padLeft(charCode.toString(16).toUpperCase(), \'0\', length);',
|
|
' }',
|
|
' ',
|
|
' #if options.trackLineAndColumn',
|
|
' function clone(object) {',
|
|
' var result = {};',
|
|
' for (var key in object) {',
|
|
' result[key] = object[key];',
|
|
' }',
|
|
' return result;',
|
|
' }',
|
|
' ',
|
|
' function advance(pos, n) {',
|
|
' var endOffset = pos.offset + n;',
|
|
' ',
|
|
' for (var offset = pos.offset; offset < endOffset; offset++) {',
|
|
' var ch = input.charAt(offset);',
|
|
' if (ch === "\\n") {',
|
|
' if (!pos.seenCR) { pos.line++; }',
|
|
' pos.column = 1;',
|
|
' pos.seenCR = false;',
|
|
' } else if (ch === "\\r" || ch === "\\u2028" || ch === "\\u2029") {',
|
|
' pos.line++;',
|
|
' pos.column = 1;',
|
|
' pos.seenCR = true;',
|
|
' } else {',
|
|
' pos.column++;',
|
|
' pos.seenCR = false;',
|
|
' }',
|
|
' }',
|
|
' ',
|
|
' pos.offset += n;',
|
|
' }',
|
|
' ',
|
|
' #end',
|
|
' function matchFailed(failure) {',
|
|
' if (#{posOffset("pos")} < #{posOffset("rightmostFailuresPos")}) {',
|
|
' return;',
|
|
' }',
|
|
' ',
|
|
' if (#{posOffset("pos")} > #{posOffset("rightmostFailuresPos")}) {',
|
|
' rightmostFailuresPos = #{posClone("pos")};',
|
|
' rightmostFailuresExpected = [];',
|
|
' }',
|
|
' ',
|
|
' rightmostFailuresExpected.push(failure);',
|
|
' }',
|
|
' ',
|
|
' #for rule in node.rules',
|
|
' #block emit(rule)',
|
|
' ',
|
|
' #end',
|
|
' ',
|
|
' function cleanupExpected(expected) {',
|
|
' expected.sort();',
|
|
' ',
|
|
' var lastExpected = null;',
|
|
' var cleanExpected = [];',
|
|
' for (var i = 0; i < expected.length; i++) {',
|
|
' if (expected[i] !== lastExpected) {',
|
|
' cleanExpected.push(expected[i]);',
|
|
' lastExpected = expected[i];',
|
|
' }',
|
|
' }',
|
|
' return cleanExpected;',
|
|
' }',
|
|
' ',
|
|
' #if !options.trackLineAndColumn',
|
|
' 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 line = 1;',
|
|
' var column = 1;',
|
|
' var seenCR = false;',
|
|
' ',
|
|
' for (var i = 0; i < Math.max(pos, rightmostFailuresPos); 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 };',
|
|
' }',
|
|
' #end',
|
|
' ',
|
|
' #if node.initializer',
|
|
' #block emit(node.initializer)',
|
|
' #end',
|
|
' ',
|
|
' var result = parseFunctions[startRule]();',
|
|
' ',
|
|
' /*',
|
|
' * The parser is now in one of the following three states:',
|
|
' *',
|
|
' * 1. The parser successfully parsed the whole input.',
|
|
' *',
|
|
' * - |result !== null|',
|
|
' * - |#{posOffset("pos")} === input.length|',
|
|
' * - |rightmostFailuresExpected| may or may not contain something',
|
|
' *',
|
|
' * 2. The parser successfully parsed only a part of the input.',
|
|
' *',
|
|
' * - |result !== null|',
|
|
' * - |#{posOffset("pos")} < input.length|',
|
|
' * - |rightmostFailuresExpected| may or may not contain something',
|
|
' *',
|
|
' * 3. The parser did not successfully parse any part of the input.',
|
|
' *',
|
|
' * - |result === null|',
|
|
' * - |#{posOffset("pos")} === 0|',
|
|
' * - |rightmostFailuresExpected| contains at least one failure',
|
|
' *',
|
|
' * All code following this comment (including called functions) must',
|
|
' * handle these states.',
|
|
' */',
|
|
' if (result === null || #{posOffset("pos")} !== input.length) {',
|
|
' var offset = Math.max(#{posOffset("pos")}, #{posOffset("rightmostFailuresPos")});',
|
|
' var found = offset < input.length ? input.charAt(offset) : null;',
|
|
' #if options.trackLineAndColumn',
|
|
' var errorPosition = #{posOffset("pos")} > #{posOffset("rightmostFailuresPos")} ? pos : rightmostFailuresPos;',
|
|
' #else',
|
|
' var errorPosition = computeErrorPosition();',
|
|
' #end',
|
|
' ',
|
|
' throw new this.SyntaxError(',
|
|
' cleanupExpected(rightmostFailuresExpected),',
|
|
' found,',
|
|
' offset,',
|
|
' errorPosition.line,',
|
|
' errorPosition.column',
|
|
' );',
|
|
' }',
|
|
' ',
|
|
' return result;',
|
|
' },',
|
|
' ',
|
|
' /* Returns the parser source code. */',
|
|
' toSource: function() { return this._source; }',
|
|
' };',
|
|
' ',
|
|
' /* Thrown when a parser encounters a syntax error. */',
|
|
' ',
|
|
' result.SyntaxError = function(expected, found, offset, line, column) {',
|
|
' function buildMessage(expected, found) {',
|
|
' var expectedHumanized, foundHumanized;',
|
|
' ',
|
|
' switch (expected.length) {',
|
|
' case 0:',
|
|
' expectedHumanized = "end of input";',
|
|
' break;',
|
|
' case 1:',
|
|
' expectedHumanized = expected[0];',
|
|
' break;',
|
|
' default:',
|
|
' expectedHumanized = expected.slice(0, expected.length - 1).join(", ")',
|
|
' + " or "',
|
|
' + expected[expected.length - 1];',
|
|
' }',
|
|
' ',
|
|
' foundHumanized = found ? quote(found) : "end of input";',
|
|
' ',
|
|
' return "Expected " + expectedHumanized + " but " + foundHumanized + " found.";',
|
|
' }',
|
|
' ',
|
|
' this.name = "SyntaxError";',
|
|
' this.expected = expected;',
|
|
' this.found = found;',
|
|
' this.message = buildMessage(expected, found);',
|
|
' this.offset = offset;',
|
|
' this.line = line;',
|
|
' this.column = column;',
|
|
' };',
|
|
' ',
|
|
' result.SyntaxError.prototype = Error.prototype;',
|
|
' ',
|
|
' return result;',
|
|
'})()'
|
|
],
|
|
rule: [
|
|
'function parse_#{node.name}() {',
|
|
' #if options.cache',
|
|
' var cacheKey = "#{node.name}@" + #{posOffset("pos")};',
|
|
' var cachedResult = cache[cacheKey];',
|
|
' if (cachedResult) {',
|
|
' pos = #{posClone("cachedResult.nextPos")};',
|
|
' return cachedResult.result;',
|
|
' }',
|
|
' ',
|
|
' #end',
|
|
' #if node.resultVars.length > 0',
|
|
' var #{node.resultVars.join(", ")};',
|
|
' #end',
|
|
' #if node.posVars.length > 0',
|
|
' var #{node.posVars.join(", ")};',
|
|
' #end',
|
|
' ',
|
|
' #if node.displayName !== null',
|
|
' reportFailures++;',
|
|
' #end',
|
|
' #block emit(node.expression)',
|
|
' #if node.displayName !== null',
|
|
' reportFailures--;',
|
|
' if (reportFailures === 0 && #{node.resultVar} === null) {',
|
|
' matchFailed(#{string(node.displayName)});',
|
|
' }',
|
|
' #end',
|
|
' #if options.cache',
|
|
' ',
|
|
' cache[cacheKey] = {',
|
|
' nextPos: #{posClone("pos")},',
|
|
' result: #{node.resultVar}',
|
|
' };',
|
|
' #end',
|
|
' return #{node.resultVar};',
|
|
'}'
|
|
],
|
|
choice: [
|
|
'#block emit(alternative)',
|
|
'#block nextAlternativesCode'
|
|
],
|
|
"choice.next": [
|
|
'if (#{node.resultVar} === null) {',
|
|
' #block code',
|
|
'}'
|
|
],
|
|
sequence: [
|
|
'#{posSave(node)};',
|
|
'#block code'
|
|
],
|
|
"sequence.iteration": [
|
|
'#block emit(element)',
|
|
'if (#{element.resultVar} !== null) {',
|
|
' #block code',
|
|
'} else {',
|
|
' #{node.resultVar} = null;',
|
|
' #{posRestore(node)};',
|
|
'}'
|
|
],
|
|
"sequence.inner": [
|
|
'#{node.resultVar} = [#{pluck(node.elements, "resultVar").join(", ")}];'
|
|
],
|
|
simple_and: [
|
|
'#{posSave(node)};',
|
|
'reportFailures++;',
|
|
'#block emit(node.expression)',
|
|
'reportFailures--;',
|
|
'if (#{node.resultVar} !== null) {',
|
|
' #{node.resultVar} = "";',
|
|
' #{posRestore(node)};',
|
|
'} else {',
|
|
' #{node.resultVar} = null;',
|
|
'}'
|
|
],
|
|
simple_not: [
|
|
'#{posSave(node)};',
|
|
'reportFailures++;',
|
|
'#block emit(node.expression)',
|
|
'reportFailures--;',
|
|
'if (#{node.resultVar} === null) {',
|
|
' #{node.resultVar} = "";',
|
|
'} else {',
|
|
' #{node.resultVar} = null;',
|
|
' #{posRestore(node)};',
|
|
'}'
|
|
],
|
|
semantic_and: [
|
|
'#{node.resultVar} = (function(#{(options.trackLineAndColumn ? ["offset", "line", "column"] : ["offset"]).concat(keys(node.params)).join(", ")}) {#{node.code}})(#{(options.trackLineAndColumn ? ["pos.offset", "pos.line", "pos.column"] : ["pos"]).concat(values(node.params)).join(", ")}) ? "" : null;'
|
|
],
|
|
semantic_not: [
|
|
'#{node.resultVar} = (function(#{(options.trackLineAndColumn ? ["offset", "line", "column"] : ["offset"]).concat(keys(node.params)).join(", ")}) {#{node.code}})(#{(options.trackLineAndColumn ? ["pos.offset", "pos.line", "pos.column"] : ["pos"]).concat(values(node.params)).join(", ")}) ? null : "";'
|
|
],
|
|
optional: [
|
|
'#block emit(node.expression)',
|
|
'#{node.resultVar} = #{node.resultVar} !== null ? #{node.resultVar} : "";'
|
|
],
|
|
zero_or_more: [
|
|
'#{node.resultVar} = [];',
|
|
'#block emit(node.expression)',
|
|
'while (#{node.expression.resultVar} !== null) {',
|
|
' #{node.resultVar}.push(#{node.expression.resultVar});',
|
|
' #block emit(node.expression)',
|
|
'}'
|
|
],
|
|
one_or_more: [
|
|
'#block emit(node.expression)',
|
|
'if (#{node.expression.resultVar} !== null) {',
|
|
' #{node.resultVar} = [];',
|
|
' while (#{node.expression.resultVar} !== null) {',
|
|
' #{node.resultVar}.push(#{node.expression.resultVar});',
|
|
' #block emit(node.expression)',
|
|
' }',
|
|
'} else {',
|
|
' #{node.resultVar} = null;',
|
|
'}'
|
|
],
|
|
action: [
|
|
'#{posSave(node)};',
|
|
'#block emit(node.expression)',
|
|
'if (#{node.resultVar} !== null) {',
|
|
' #{node.resultVar} = (function(#{(options.trackLineAndColumn ? ["offset", "line", "column"] : ["offset"]).concat(keys(node.params)).join(", ")}) {#{node.code}})(#{(options.trackLineAndColumn ? [node.posVar + ".offset", node.posVar + ".line", node.posVar + ".column"] : [node.posVar]).concat(values(node.params)).join(", ")});',
|
|
'}',
|
|
'if (#{node.resultVar} === null) {',
|
|
' #{posRestore(node)};',
|
|
'}'
|
|
],
|
|
rule_ref: [
|
|
'#{node.resultVar} = parse_#{node.name}();'
|
|
],
|
|
literal: [
|
|
'#if node.value.length === 0',
|
|
' #{node.resultVar} = "";',
|
|
'#else',
|
|
' #if !node.ignoreCase',
|
|
' #if node.value.length === 1',
|
|
' if (input.charCodeAt(#{posOffset("pos")}) === #{node.value.charCodeAt(0)}) {',
|
|
' #else',
|
|
' if (input.substr(#{posOffset("pos")}, #{node.value.length}) === #{string(node.value)}) {',
|
|
' #end',
|
|
' #else',
|
|
/*
|
|
* One-char literals are not optimized when case-insensitive
|
|
* matching is enabled. This is because there is no simple way to
|
|
* lowercase a character code that works for character outside ASCII
|
|
* letters. Moreover, |toLowerCase| can change string length,
|
|
* meaning the result of lowercasing a character can be more
|
|
* characters.
|
|
*/
|
|
' if (input.substr(#{posOffset("pos")}, #{node.value.length}).toLowerCase() === #{string(node.value.toLowerCase())}) {',
|
|
' #end',
|
|
' #if !node.ignoreCase',
|
|
' #{node.resultVar} = #{string(node.value)};',
|
|
' #else',
|
|
' #{node.resultVar} = input.substr(#{posOffset("pos")}, #{node.value.length});',
|
|
' #end',
|
|
' #{posAdvance(node.value.length)};',
|
|
' } else {',
|
|
' #{node.resultVar} = null;',
|
|
' if (reportFailures === 0) {',
|
|
' matchFailed(#{string(string(node.value))});',
|
|
' }',
|
|
' }',
|
|
'#end'
|
|
],
|
|
any: [
|
|
'if (input.length > #{posOffset("pos")}) {',
|
|
' #{node.resultVar} = input.charAt(#{posOffset("pos")});',
|
|
' #{posAdvance(1)};',
|
|
'} else {',
|
|
' #{node.resultVar} = null;',
|
|
' if (reportFailures === 0) {',
|
|
' matchFailed("any character");',
|
|
' }',
|
|
'}'
|
|
],
|
|
"class": [
|
|
'if (#{regexp}.test(input.charAt(#{posOffset("pos")}))) {',
|
|
' #{node.resultVar} = input.charAt(#{posOffset("pos")});',
|
|
' #{posAdvance(1)};',
|
|
'} else {',
|
|
' #{node.resultVar} = null;',
|
|
' if (reportFailures === 0) {',
|
|
' matchFailed(#{string(node.rawText)});',
|
|
' }',
|
|
'}'
|
|
]
|
|
};
|
|
|
|
for (name in sources) {
|
|
templates[name] = Codie.template(sources[name].join('\n'));
|
|
}
|
|
|
|
return templates;
|
|
})();
|
|
|
|
function fill(name, vars) {
|
|
vars.string = quote;
|
|
vars.pluck = pluck;
|
|
vars.keys = keys;
|
|
vars.values = values;
|
|
vars.emit = emit;
|
|
vars.options = options;
|
|
|
|
/* Position-handling macros */
|
|
if (options.trackLineAndColumn) {
|
|
vars.posInit = function(name) {
|
|
return "var "
|
|
+ name
|
|
+ " = "
|
|
+ "{ offset: 0, line: 1, column: 1, seenCR: false }";
|
|
};
|
|
vars.posClone = function(name) { return "clone(" + name + ")"; };
|
|
vars.posOffset = function(name) { return name + ".offset"; };
|
|
|
|
vars.posAdvance = function(n) { return "advance(pos, " + n + ")"; };
|
|
} else {
|
|
vars.posInit = function(name) { return "var " + name + " = 0"; };
|
|
vars.posClone = function(name) { return name; };
|
|
vars.posOffset = function(name) { return name; };
|
|
|
|
vars.posAdvance = function(n) {
|
|
return n === 1 ? "pos++" : "pos += " + n;
|
|
};
|
|
}
|
|
vars.posSave = function(node) {
|
|
return node.posVar + " = " + vars.posClone("pos");
|
|
};
|
|
vars.posRestore = function(node) {
|
|
return "pos" + " = " + vars.posClone(node.posVar);
|
|
};
|
|
|
|
return templates[name](vars);
|
|
}
|
|
|
|
function emitSimple(name) {
|
|
return function(node) { return fill(name, { node: node }); };
|
|
}
|
|
|
|
var emit = buildNodeVisitor({
|
|
grammar: emitSimple("grammar"),
|
|
|
|
initializer: function(node) { return node.code; },
|
|
|
|
rule: emitSimple("rule"),
|
|
|
|
/*
|
|
* The contract for all code fragments generated by the following functions
|
|
* is as follows.
|
|
*
|
|
* The code fragment tries to match a part of the input starting with the
|
|
* position indicated in |pos|. That position may point past the end of the
|
|
* input.
|
|
*
|
|
* * If the code fragment matches the input, it advances |pos| to point to
|
|
* the first chracter following the matched part of the input and sets
|
|
* variable with a name stored in |node.resultVar| to an appropriate
|
|
* value. This value is always non-|null|.
|
|
*
|
|
* * If the code fragment does not match the input, it returns with |pos|
|
|
* set to the original value and it sets a variable with a name stored in
|
|
* |node.resultVar| to |null|.
|
|
*
|
|
* The code can use variables with names stored in |resultVar| and |posVar|
|
|
* properties of the current node's subnodes. It can't use any other
|
|
* variables.
|
|
*/
|
|
|
|
choice: function(node) {
|
|
var code, nextAlternativesCode;
|
|
|
|
for (var i = node.alternatives.length - 1; i >= 0; i--) {
|
|
nextAlternativesCode = i !== node.alternatives.length - 1
|
|
? fill("choice.next", { node: node, code: code })
|
|
: '';
|
|
code = fill("choice", {
|
|
alternative: node.alternatives[i],
|
|
nextAlternativesCode: nextAlternativesCode
|
|
});
|
|
}
|
|
|
|
return code;
|
|
},
|
|
|
|
sequence: function(node) {
|
|
var code = fill("sequence.inner", { node: node });
|
|
|
|
for (var i = node.elements.length - 1; i >= 0; i--) {
|
|
code = fill("sequence.iteration", {
|
|
node: node,
|
|
element: node.elements[i],
|
|
code: code
|
|
});
|
|
}
|
|
|
|
return fill("sequence", { node: node, code: code });
|
|
},
|
|
|
|
labeled: function(node) { return emit(node.expression); },
|
|
|
|
simple_and: emitSimple("simple_and"),
|
|
simple_not: emitSimple("simple_not"),
|
|
semantic_and: emitSimple("semantic_and"),
|
|
semantic_not: emitSimple("semantic_not"),
|
|
optional: emitSimple("optional"),
|
|
zero_or_more: emitSimple("zero_or_more"),
|
|
one_or_more: emitSimple("one_or_more"),
|
|
action: emitSimple("action"),
|
|
rule_ref: emitSimple("rule_ref"),
|
|
literal: emitSimple("literal"),
|
|
any: emitSimple("any"),
|
|
|
|
"class": function(node) {
|
|
var regexp;
|
|
|
|
if (node.parts.length > 0) {
|
|
regexp = '/^['
|
|
+ (node.inverted ? '^' : '')
|
|
+ map(node.parts, function(part) {
|
|
return part instanceof Array
|
|
? quoteForRegexpClass(part[0])
|
|
+ '-'
|
|
+ quoteForRegexpClass(part[1])
|
|
: quoteForRegexpClass(part);
|
|
}).join('')
|
|
+ ']/' + (node.ignoreCase ? 'i' : '');
|
|
} else {
|
|
/*
|
|
* Stupid IE considers regexps /[]/ and /[^]/ syntactically invalid, so
|
|
* we translate them into euqivalents it can handle.
|
|
*/
|
|
regexp = node.inverted ? '/^[\\S\\s]/' : '/^(?!)/';
|
|
}
|
|
|
|
return fill("class", { node: node, regexp: regexp });
|
|
}
|
|
});
|
|
|
|
return emit(ast);
|
|
};
|
|
|
|
return PEG;
|
|
|
|
})();
|
|
|
|
if (typeof module !== "undefined") {
|
|
module.exports = PEG;
|
|
}
|