|
|
|
@ -98,229 +98,229 @@ PEG.compiler.emitter = function(ast) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return formatCode(
|
|
|
|
|
"(function(){",
|
|
|
|
|
" /* Generated by PEG.js @VERSION (http://pegjs.majda.cz/). */",
|
|
|
|
|
" ",
|
|
|
|
|
" 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 = {",
|
|
|
|
|
" ${parseFunctionTableItems}",
|
|
|
|
|
" };",
|
|
|
|
|
" ",
|
|
|
|
|
" if (startRule !== undefined) {",
|
|
|
|
|
" if (parseFunctions[startRule] === undefined) {",
|
|
|
|
|
" throw new Error(\"Invalid rule name: \" + quote(startRule) + \".\");",
|
|
|
|
|
" }",
|
|
|
|
|
" } else {",
|
|
|
|
|
" startRule = ${startRule|string};",
|
|
|
|
|
" }",
|
|
|
|
|
" ",
|
|
|
|
|
" var pos = 0;",
|
|
|
|
|
" var reportFailures = 0;", // 0 = report, anything > 0 = do not report
|
|
|
|
|
" var rightmostFailuresPos = 0;",
|
|
|
|
|
" var rightmostFailuresExpected = [];",
|
|
|
|
|
" var cache = {};",
|
|
|
|
|
" ",
|
|
|
|
|
'(function(){',
|
|
|
|
|
' /* Generated by PEG.js @VERSION (http://pegjs.majda.cz/). */',
|
|
|
|
|
' ',
|
|
|
|
|
' 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 = {',
|
|
|
|
|
' ${parseFunctionTableItems}',
|
|
|
|
|
' };',
|
|
|
|
|
' ',
|
|
|
|
|
' if (startRule !== undefined) {',
|
|
|
|
|
' if (parseFunctions[startRule] === undefined) {',
|
|
|
|
|
' throw new Error("Invalid rule name: " + quote(startRule) + ".");',
|
|
|
|
|
' }',
|
|
|
|
|
' } else {',
|
|
|
|
|
' startRule = ${startRule|string};',
|
|
|
|
|
' }',
|
|
|
|
|
' ',
|
|
|
|
|
' var pos = 0;',
|
|
|
|
|
' var reportFailures = 0;', // 0 = report, anything > 0 = do not report
|
|
|
|
|
' var rightmostFailuresPos = 0;',
|
|
|
|
|
' var rightmostFailuresExpected = [];',
|
|
|
|
|
' var cache = {};',
|
|
|
|
|
' ',
|
|
|
|
|
/* 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;",
|
|
|
|
|
" }",
|
|
|
|
|
" ",
|
|
|
|
|
' 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);",
|
|
|
|
|
" }",
|
|
|
|
|
" ",
|
|
|
|
|
' 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);',
|
|
|
|
|
' }',
|
|
|
|
|
' ',
|
|
|
|
|
/* 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)",
|
|
|
|
|
" + '\"';",
|
|
|
|
|
" }",
|
|
|
|
|
" ",
|
|
|
|
|
" function matchFailed(failure) {",
|
|
|
|
|
" if (pos < rightmostFailuresPos) {",
|
|
|
|
|
" return;",
|
|
|
|
|
" }",
|
|
|
|
|
" ",
|
|
|
|
|
" if (pos > rightmostFailuresPos) {",
|
|
|
|
|
" rightmostFailuresPos = pos;",
|
|
|
|
|
" rightmostFailuresExpected = [];",
|
|
|
|
|
" }",
|
|
|
|
|
" ",
|
|
|
|
|
" rightmostFailuresExpected.push(failure);",
|
|
|
|
|
" }",
|
|
|
|
|
" ",
|
|
|
|
|
" ${parseFunctionDefinitions}",
|
|
|
|
|
" ",
|
|
|
|
|
" function buildErrorMessage() {",
|
|
|
|
|
" function buildExpected(failuresExpected) {",
|
|
|
|
|
" failuresExpected.sort();",
|
|
|
|
|
" ",
|
|
|
|
|
" var lastFailure = null;",
|
|
|
|
|
" var failuresExpectedUnique = [];",
|
|
|
|
|
" for (var i = 0; i < failuresExpected.length; i++) {",
|
|
|
|
|
" if (failuresExpected[i] !== lastFailure) {",
|
|
|
|
|
" failuresExpectedUnique.push(failuresExpected[i]);",
|
|
|
|
|
" lastFailure = failuresExpected[i];",
|
|
|
|
|
" }",
|
|
|
|
|
" }",
|
|
|
|
|
" ",
|
|
|
|
|
" switch (failuresExpectedUnique.length) {",
|
|
|
|
|
" case 0:",
|
|
|
|
|
" return 'end of input';",
|
|
|
|
|
" case 1:",
|
|
|
|
|
" return failuresExpectedUnique[0];",
|
|
|
|
|
" default:",
|
|
|
|
|
" return failuresExpectedUnique.slice(0, failuresExpectedUnique.length - 1).join(', ')",
|
|
|
|
|
" + ' or '",
|
|
|
|
|
" + failuresExpectedUnique[failuresExpectedUnique.length - 1];",
|
|
|
|
|
" }",
|
|
|
|
|
" }",
|
|
|
|
|
" ",
|
|
|
|
|
" var expected = buildExpected(rightmostFailuresExpected);",
|
|
|
|
|
" var actualPos = Math.max(pos, rightmostFailuresPos);",
|
|
|
|
|
" var actual = actualPos < input.length",
|
|
|
|
|
" ? quote(input.charAt(actualPos))",
|
|
|
|
|
" : 'end of input';",
|
|
|
|
|
" ",
|
|
|
|
|
" return 'Expected ' + expected + ' but ' + actual + ' found.';",
|
|
|
|
|
" }",
|
|
|
|
|
" ",
|
|
|
|
|
" function computeErrorPosition() {",
|
|
|
|
|
" /*",
|
|
|
|
|
" * The first idea was to use |String.split| to break the input up to the",
|
|
|
|
|
" * error position along newlines and derive the line and column from",
|
|
|
|
|
" * there. However IE's |split| implementation is so broken that it was",
|
|
|
|
|
" * enough to prevent it.",
|
|
|
|
|
" */",
|
|
|
|
|
" ",
|
|
|
|
|
" var line = 1;",
|
|
|
|
|
" var column = 1;",
|
|
|
|
|
" var seenCR = false;",
|
|
|
|
|
" ",
|
|
|
|
|
" for (var i = 0; i < 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 };",
|
|
|
|
|
" }",
|
|
|
|
|
" ",
|
|
|
|
|
" ${initializerCode}",
|
|
|
|
|
" ",
|
|
|
|
|
" 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 errorPosition = computeErrorPosition();",
|
|
|
|
|
" throw new this.SyntaxError(",
|
|
|
|
|
" buildErrorMessage(),",
|
|
|
|
|
" 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(message, line, column) {",
|
|
|
|
|
" this.name = 'SyntaxError';",
|
|
|
|
|
" this.message = message;",
|
|
|
|
|
" this.line = line;",
|
|
|
|
|
" this.column = column;",
|
|
|
|
|
" };",
|
|
|
|
|
" ",
|
|
|
|
|
" result.SyntaxError.prototype = Error.prototype;",
|
|
|
|
|
" ",
|
|
|
|
|
" return result;",
|
|
|
|
|
"})()",
|
|
|
|
|
' 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)',
|
|
|
|
|
' + \'"\';',
|
|
|
|
|
' }',
|
|
|
|
|
' ',
|
|
|
|
|
' function matchFailed(failure) {',
|
|
|
|
|
' if (pos < rightmostFailuresPos) {',
|
|
|
|
|
' return;',
|
|
|
|
|
' }',
|
|
|
|
|
' ',
|
|
|
|
|
' if (pos > rightmostFailuresPos) {',
|
|
|
|
|
' rightmostFailuresPos = pos;',
|
|
|
|
|
' rightmostFailuresExpected = [];',
|
|
|
|
|
' }',
|
|
|
|
|
' ',
|
|
|
|
|
' rightmostFailuresExpected.push(failure);',
|
|
|
|
|
' }',
|
|
|
|
|
' ',
|
|
|
|
|
' ${parseFunctionDefinitions}',
|
|
|
|
|
' ',
|
|
|
|
|
' function buildErrorMessage() {',
|
|
|
|
|
' function buildExpected(failuresExpected) {',
|
|
|
|
|
' failuresExpected.sort();',
|
|
|
|
|
' ',
|
|
|
|
|
' var lastFailure = null;',
|
|
|
|
|
' var failuresExpectedUnique = [];',
|
|
|
|
|
' for (var i = 0; i < failuresExpected.length; i++) {',
|
|
|
|
|
' if (failuresExpected[i] !== lastFailure) {',
|
|
|
|
|
' failuresExpectedUnique.push(failuresExpected[i]);',
|
|
|
|
|
' lastFailure = failuresExpected[i];',
|
|
|
|
|
' }',
|
|
|
|
|
' }',
|
|
|
|
|
' ',
|
|
|
|
|
' switch (failuresExpectedUnique.length) {',
|
|
|
|
|
' case 0:',
|
|
|
|
|
' return "end of input";',
|
|
|
|
|
' case 1:',
|
|
|
|
|
' return failuresExpectedUnique[0];',
|
|
|
|
|
' default:',
|
|
|
|
|
' return failuresExpectedUnique.slice(0, failuresExpectedUnique.length - 1).join(", ")',
|
|
|
|
|
' + " or "',
|
|
|
|
|
' + failuresExpectedUnique[failuresExpectedUnique.length - 1];',
|
|
|
|
|
' }',
|
|
|
|
|
' }',
|
|
|
|
|
' ',
|
|
|
|
|
' var expected = buildExpected(rightmostFailuresExpected);',
|
|
|
|
|
' var actualPos = Math.max(pos, rightmostFailuresPos);',
|
|
|
|
|
' var actual = actualPos < input.length',
|
|
|
|
|
' ? quote(input.charAt(actualPos))',
|
|
|
|
|
' : "end of input";',
|
|
|
|
|
' ',
|
|
|
|
|
' return "Expected " + expected + " but " + actual + " found.";',
|
|
|
|
|
' }',
|
|
|
|
|
' ',
|
|
|
|
|
' function computeErrorPosition() {',
|
|
|
|
|
' /*',
|
|
|
|
|
' * The first idea was to use |String.split| to break the input up to the',
|
|
|
|
|
' * error position along newlines and derive the line and column from',
|
|
|
|
|
' * there. However IE\'s |split| implementation is so broken that it was',
|
|
|
|
|
' * enough to prevent it.',
|
|
|
|
|
' */',
|
|
|
|
|
' ',
|
|
|
|
|
' var line = 1;',
|
|
|
|
|
' var column = 1;',
|
|
|
|
|
' var seenCR = false;',
|
|
|
|
|
' ',
|
|
|
|
|
' for (var i = 0; i < 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 };',
|
|
|
|
|
' }',
|
|
|
|
|
' ',
|
|
|
|
|
' ${initializerCode}',
|
|
|
|
|
' ',
|
|
|
|
|
' 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 errorPosition = computeErrorPosition();',
|
|
|
|
|
' throw new this.SyntaxError(',
|
|
|
|
|
' buildErrorMessage(),',
|
|
|
|
|
' 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(message, line, column) {',
|
|
|
|
|
' this.name = "SyntaxError";',
|
|
|
|
|
' this.message = message;',
|
|
|
|
|
' this.line = line;',
|
|
|
|
|
' this.column = column;',
|
|
|
|
|
' };',
|
|
|
|
|
' ',
|
|
|
|
|
' result.SyntaxError.prototype = Error.prototype;',
|
|
|
|
|
' ',
|
|
|
|
|
' return result;',
|
|
|
|
|
'})()',
|
|
|
|
|
{
|
|
|
|
|
initializerCode: initializerCode,
|
|
|
|
|
parseFunctionTableItems: parseFunctionTableItems.join(",\n"),
|
|
|
|
|
parseFunctionDefinitions: parseFunctionDefinitions.join("\n\n"),
|
|
|
|
|
parseFunctionTableItems: parseFunctionTableItems.join(',\n'),
|
|
|
|
|
parseFunctionDefinitions: parseFunctionDefinitions.join('\n\n'),
|
|
|
|
|
startRule: node.startRule
|
|
|
|
|
}
|
|
|
|
|
);
|
|
|
|
@ -339,8 +339,8 @@ PEG.compiler.emitter = function(ast) {
|
|
|
|
|
var resultVars = map(range(node.resultStackDepth), resultVar);
|
|
|
|
|
var posVars = map(range(node.posStackDepth), posVar);
|
|
|
|
|
|
|
|
|
|
var resultVarsCode = resultVars.length > 0 ? "var " + resultVars.join(", ") + ";" : "";
|
|
|
|
|
var posVarsCode = posVars.length > 0 ? "var " + posVars.join(", ") + ";" : "";
|
|
|
|
|
var resultVarsCode = resultVars.length > 0 ? 'var ' + resultVars.join(', ') + ';' : '';
|
|
|
|
|
var posVarsCode = posVars.length > 0 ? 'var ' + posVars.join(', ') + ';' : '';
|
|
|
|
|
|
|
|
|
|
var setReportFailuresCode;
|
|
|
|
|
var restoreReportFailuresCode;
|
|
|
|
@ -348,15 +348,15 @@ PEG.compiler.emitter = function(ast) {
|
|
|
|
|
|
|
|
|
|
if (node.displayName !== null) {
|
|
|
|
|
setReportFailuresCode = formatCode(
|
|
|
|
|
"reportFailures++;"
|
|
|
|
|
'reportFailures++;'
|
|
|
|
|
);
|
|
|
|
|
restoreReportFailuresCode = formatCode(
|
|
|
|
|
"reportFailures--;"
|
|
|
|
|
'reportFailures--;'
|
|
|
|
|
);
|
|
|
|
|
reportFailureCode = formatCode(
|
|
|
|
|
"if (reportFailures === 0 && ${resultVar} === null) {",
|
|
|
|
|
" matchFailed(${displayName|string});",
|
|
|
|
|
"}",
|
|
|
|
|
'if (reportFailures === 0 && ${resultVar} === null) {',
|
|
|
|
|
' matchFailed(${displayName|string});',
|
|
|
|
|
'}',
|
|
|
|
|
{
|
|
|
|
|
displayName: node.displayName,
|
|
|
|
|
resultVar: resultVar(context.resultIndex)
|
|
|
|
@ -369,28 +369,28 @@ PEG.compiler.emitter = function(ast) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return formatCode(
|
|
|
|
|
"function parse_${name}() {",
|
|
|
|
|
" var cacheKey = '${name}@' + pos;",
|
|
|
|
|
" var cachedResult = cache[cacheKey];",
|
|
|
|
|
" if (cachedResult) {",
|
|
|
|
|
" pos = cachedResult.nextPos;",
|
|
|
|
|
" return cachedResult.result;",
|
|
|
|
|
" }",
|
|
|
|
|
" ",
|
|
|
|
|
" ${resultVarsCode}",
|
|
|
|
|
" ${posVarsCode}",
|
|
|
|
|
" ",
|
|
|
|
|
" ${setReportFailuresCode}",
|
|
|
|
|
" ${code}",
|
|
|
|
|
" ${restoreReportFailuresCode}",
|
|
|
|
|
" ${reportFailureCode}",
|
|
|
|
|
" ",
|
|
|
|
|
" cache[cacheKey] = {",
|
|
|
|
|
" nextPos: pos,",
|
|
|
|
|
" result: ${resultVar}",
|
|
|
|
|
" };",
|
|
|
|
|
" return ${resultVar};",
|
|
|
|
|
"}",
|
|
|
|
|
'function parse_${name}() {',
|
|
|
|
|
' var cacheKey = "${name}@" + pos;',
|
|
|
|
|
' var cachedResult = cache[cacheKey];',
|
|
|
|
|
' if (cachedResult) {',
|
|
|
|
|
' pos = cachedResult.nextPos;',
|
|
|
|
|
' return cachedResult.result;',
|
|
|
|
|
' }',
|
|
|
|
|
' ',
|
|
|
|
|
' ${resultVarsCode}',
|
|
|
|
|
' ${posVarsCode}',
|
|
|
|
|
' ',
|
|
|
|
|
' ${setReportFailuresCode}',
|
|
|
|
|
' ${code}',
|
|
|
|
|
' ${restoreReportFailuresCode}',
|
|
|
|
|
' ${reportFailureCode}',
|
|
|
|
|
' ',
|
|
|
|
|
' cache[cacheKey] = {',
|
|
|
|
|
' nextPos: pos,',
|
|
|
|
|
' result: ${resultVar}',
|
|
|
|
|
' };',
|
|
|
|
|
' return ${resultVar};',
|
|
|
|
|
'}',
|
|
|
|
|
{
|
|
|
|
|
name: node.name,
|
|
|
|
|
resultVarsCode: resultVarsCode,
|
|
|
|
@ -440,18 +440,18 @@ PEG.compiler.emitter = function(ast) {
|
|
|
|
|
for (var i = node.alternatives.length - 1; i >= 0; i--) {
|
|
|
|
|
nextAlternativesCode = i !== node.alternatives.length - 1
|
|
|
|
|
? formatCode(
|
|
|
|
|
"if (${resultVar} === null) {",
|
|
|
|
|
" ${code}",
|
|
|
|
|
"}",
|
|
|
|
|
'if (${resultVar} === null) {',
|
|
|
|
|
' ${code}',
|
|
|
|
|
'}',
|
|
|
|
|
{
|
|
|
|
|
code: code,
|
|
|
|
|
resultVar: resultVar(context.resultIndex)
|
|
|
|
|
}
|
|
|
|
|
)
|
|
|
|
|
: "";
|
|
|
|
|
: '';
|
|
|
|
|
code = formatCode(
|
|
|
|
|
"${currentAlternativeCode}",
|
|
|
|
|
"${nextAlternativesCode}",
|
|
|
|
|
'${currentAlternativeCode}',
|
|
|
|
|
'${nextAlternativesCode}',
|
|
|
|
|
{
|
|
|
|
|
currentAlternativeCode: emit(node.alternatives[i], context),
|
|
|
|
|
nextAlternativesCode: nextAlternativesCode
|
|
|
|
@ -468,10 +468,10 @@ PEG.compiler.emitter = function(ast) {
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
var code = formatCode(
|
|
|
|
|
"${resultVar} = ${elementResultVarArray};",
|
|
|
|
|
'${resultVar} = ${elementResultVarArray};',
|
|
|
|
|
{
|
|
|
|
|
resultVar: resultVar(context.resultIndex),
|
|
|
|
|
elementResultVarArray: "[" + elementResultVars.join(", ") + "]"
|
|
|
|
|
elementResultVarArray: '[' + elementResultVars.join(', ') + ']'
|
|
|
|
|
}
|
|
|
|
|
);
|
|
|
|
|
var elementContext;
|
|
|
|
@ -482,13 +482,13 @@ PEG.compiler.emitter = function(ast) {
|
|
|
|
|
posIndex: context.posIndex + 1
|
|
|
|
|
};
|
|
|
|
|
code = formatCode(
|
|
|
|
|
"${elementCode}",
|
|
|
|
|
"if (${elementResultVar} !== null) {",
|
|
|
|
|
" ${code}",
|
|
|
|
|
"} else {",
|
|
|
|
|
" ${resultVar} = null;",
|
|
|
|
|
" pos = ${posVar};",
|
|
|
|
|
"}",
|
|
|
|
|
'${elementCode}',
|
|
|
|
|
'if (${elementResultVar} !== null) {',
|
|
|
|
|
' ${code}',
|
|
|
|
|
'} else {',
|
|
|
|
|
' ${resultVar} = null;',
|
|
|
|
|
' pos = ${posVar};',
|
|
|
|
|
'}',
|
|
|
|
|
{
|
|
|
|
|
elementCode: emit(node.elements[i], elementContext),
|
|
|
|
|
elementResultVar: elementResultVars[i],
|
|
|
|
@ -500,8 +500,8 @@ PEG.compiler.emitter = function(ast) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return formatCode(
|
|
|
|
|
"${posVar} = pos;",
|
|
|
|
|
"${code}",
|
|
|
|
|
'${posVar} = pos;',
|
|
|
|
|
'${code}',
|
|
|
|
|
{
|
|
|
|
|
code: code,
|
|
|
|
|
posVar: posVar(context.posIndex)
|
|
|
|
@ -520,16 +520,16 @@ PEG.compiler.emitter = function(ast) {
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
return formatCode(
|
|
|
|
|
"${posVar} = pos;",
|
|
|
|
|
"reportFailures++;",
|
|
|
|
|
"${expressionCode}",
|
|
|
|
|
"reportFailures--;",
|
|
|
|
|
"if (${resultVar} !== null) {",
|
|
|
|
|
" ${resultVar} = '';",
|
|
|
|
|
" pos = ${posVar};",
|
|
|
|
|
"} else {",
|
|
|
|
|
" ${resultVar} = null;",
|
|
|
|
|
"}",
|
|
|
|
|
'${posVar} = pos;',
|
|
|
|
|
'reportFailures++;',
|
|
|
|
|
'${expressionCode}',
|
|
|
|
|
'reportFailures--;',
|
|
|
|
|
'if (${resultVar} !== null) {',
|
|
|
|
|
' ${resultVar} = "";',
|
|
|
|
|
' pos = ${posVar};',
|
|
|
|
|
'} else {',
|
|
|
|
|
' ${resultVar} = null;',
|
|
|
|
|
'}',
|
|
|
|
|
{
|
|
|
|
|
expressionCode: emit(node.expression, expressionContext),
|
|
|
|
|
posVar: posVar(context.posIndex),
|
|
|
|
@ -545,16 +545,16 @@ PEG.compiler.emitter = function(ast) {
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
return formatCode(
|
|
|
|
|
"${posVar} = pos;",
|
|
|
|
|
"reportFailures++;",
|
|
|
|
|
"${expressionCode}",
|
|
|
|
|
"reportFailures--;",
|
|
|
|
|
"if (${resultVar} === null) {",
|
|
|
|
|
" ${resultVar} = '';",
|
|
|
|
|
"} else {",
|
|
|
|
|
" ${resultVar} = null;",
|
|
|
|
|
" pos = ${posVar};",
|
|
|
|
|
"}",
|
|
|
|
|
'${posVar} = pos;',
|
|
|
|
|
'reportFailures++;',
|
|
|
|
|
'${expressionCode}',
|
|
|
|
|
'reportFailures--;',
|
|
|
|
|
'if (${resultVar} === null) {',
|
|
|
|
|
' ${resultVar} = "";',
|
|
|
|
|
'} else {',
|
|
|
|
|
' ${resultVar} = null;',
|
|
|
|
|
' pos = ${posVar};',
|
|
|
|
|
'}',
|
|
|
|
|
{
|
|
|
|
|
expressionCode: emit(node.expression, expressionContext),
|
|
|
|
|
posVar: posVar(context.posIndex),
|
|
|
|
@ -565,7 +565,7 @@ PEG.compiler.emitter = function(ast) {
|
|
|
|
|
|
|
|
|
|
semantic_and: function(node, context) {
|
|
|
|
|
return formatCode(
|
|
|
|
|
"${resultVar} = (function() {${actionCode}})() ? '' : null;",
|
|
|
|
|
'${resultVar} = (function() {${actionCode}})() ? "" : null;',
|
|
|
|
|
{
|
|
|
|
|
actionCode: node.code,
|
|
|
|
|
resultVar: resultVar(context.resultIndex)
|
|
|
|
@ -575,7 +575,7 @@ PEG.compiler.emitter = function(ast) {
|
|
|
|
|
|
|
|
|
|
semantic_not: function(node, context) {
|
|
|
|
|
return formatCode(
|
|
|
|
|
"${resultVar} = (function() {${actionCode}})() ? null : '';",
|
|
|
|
|
'${resultVar} = (function() {${actionCode}})() ? null : "";',
|
|
|
|
|
{
|
|
|
|
|
actionCode: node.code,
|
|
|
|
|
resultVar: resultVar(context.resultIndex)
|
|
|
|
@ -585,8 +585,8 @@ PEG.compiler.emitter = function(ast) {
|
|
|
|
|
|
|
|
|
|
optional: function(node, context) {
|
|
|
|
|
return formatCode(
|
|
|
|
|
"${expressionCode}",
|
|
|
|
|
"${resultVar} = ${resultVar} !== null ? ${resultVar} : '';",
|
|
|
|
|
'${expressionCode}',
|
|
|
|
|
'${resultVar} = ${resultVar} !== null ? ${resultVar} : "";',
|
|
|
|
|
{
|
|
|
|
|
expressionCode: emit(node.expression, context),
|
|
|
|
|
resultVar: resultVar(context.resultIndex)
|
|
|
|
@ -601,12 +601,12 @@ PEG.compiler.emitter = function(ast) {
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
return formatCode(
|
|
|
|
|
"${resultVar} = [];",
|
|
|
|
|
"${expressionCode}",
|
|
|
|
|
"while (${expressionResultVar} !== null) {",
|
|
|
|
|
" ${resultVar}.push(${expressionResultVar});",
|
|
|
|
|
" ${expressionCode}",
|
|
|
|
|
"}",
|
|
|
|
|
'${resultVar} = [];',
|
|
|
|
|
'${expressionCode}',
|
|
|
|
|
'while (${expressionResultVar} !== null) {',
|
|
|
|
|
' ${resultVar}.push(${expressionResultVar});',
|
|
|
|
|
' ${expressionCode}',
|
|
|
|
|
'}',
|
|
|
|
|
{
|
|
|
|
|
expressionCode: emit(node.expression, expressionContext),
|
|
|
|
|
expressionResultVar: resultVar(context.resultIndex + 1),
|
|
|
|
@ -622,16 +622,16 @@ PEG.compiler.emitter = function(ast) {
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
return formatCode(
|
|
|
|
|
"${expressionCode}",
|
|
|
|
|
"if (${expressionResultVar} !== null) {",
|
|
|
|
|
" ${resultVar} = [];",
|
|
|
|
|
" while (${expressionResultVar} !== null) {",
|
|
|
|
|
" ${resultVar}.push(${expressionResultVar});",
|
|
|
|
|
" ${expressionCode}",
|
|
|
|
|
" }",
|
|
|
|
|
"} else {",
|
|
|
|
|
" ${resultVar} = null;",
|
|
|
|
|
"}",
|
|
|
|
|
'${expressionCode}',
|
|
|
|
|
'if (${expressionResultVar} !== null) {',
|
|
|
|
|
' ${resultVar} = [];',
|
|
|
|
|
' while (${expressionResultVar} !== null) {',
|
|
|
|
|
' ${resultVar}.push(${expressionResultVar});',
|
|
|
|
|
' ${expressionCode}',
|
|
|
|
|
' }',
|
|
|
|
|
'} else {',
|
|
|
|
|
' ${resultVar} = null;',
|
|
|
|
|
'}',
|
|
|
|
|
{
|
|
|
|
|
expressionCode: emit(node.expression, expressionContext),
|
|
|
|
|
expressionResultVar: resultVar(context.resultIndex + 1),
|
|
|
|
@ -667,7 +667,7 @@ PEG.compiler.emitter = function(ast) {
|
|
|
|
|
for (var i = 0; i < elementsLength; i++) {
|
|
|
|
|
if (elements[i].type === "labeled") {
|
|
|
|
|
formalParams.push(elements[i].label);
|
|
|
|
|
actualParams.push(resultVar(context.resultIndex) + "[" + i + "]");
|
|
|
|
|
actualParams.push(resultVar(context.resultIndex) + '[' + i + ']');
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else if (node.expression.type === "labeled") {
|
|
|
|
@ -679,19 +679,19 @@ PEG.compiler.emitter = function(ast) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return formatCode(
|
|
|
|
|
"${posVar} = pos;",
|
|
|
|
|
"${expressionCode}",
|
|
|
|
|
"if (${resultVar} !== null) {",
|
|
|
|
|
" ${resultVar} = (function(${formalParams}) {${actionCode}})(${actualParams});",
|
|
|
|
|
"}",
|
|
|
|
|
"if (${resultVar} === null) {",
|
|
|
|
|
" pos = ${posVar};",
|
|
|
|
|
"}",
|
|
|
|
|
'${posVar} = pos;',
|
|
|
|
|
'${expressionCode}',
|
|
|
|
|
'if (${resultVar} !== null) {',
|
|
|
|
|
' ${resultVar} = (function(${formalParams}) {${actionCode}})(${actualParams});',
|
|
|
|
|
'}',
|
|
|
|
|
'if (${resultVar} === null) {',
|
|
|
|
|
' pos = ${posVar};',
|
|
|
|
|
'}',
|
|
|
|
|
{
|
|
|
|
|
expressionCode: emit(node.expression, expressionContext),
|
|
|
|
|
actionCode: node.code,
|
|
|
|
|
formalParams: formalParams.join(", "),
|
|
|
|
|
actualParams: actualParams.join(", "),
|
|
|
|
|
formalParams: formalParams.join(', '),
|
|
|
|
|
actualParams: actualParams.join(', '),
|
|
|
|
|
posVar: posVar(context.posIndex),
|
|
|
|
|
resultVar: resultVar(context.resultIndex)
|
|
|
|
|
}
|
|
|
|
@ -700,9 +700,9 @@ PEG.compiler.emitter = function(ast) {
|
|
|
|
|
|
|
|
|
|
rule_ref: function(node, context) {
|
|
|
|
|
return formatCode(
|
|
|
|
|
"${resultVar} = ${ruleMethod}();",
|
|
|
|
|
'${resultVar} = ${ruleMethod}();',
|
|
|
|
|
{
|
|
|
|
|
ruleMethod: "parse_" + node.name,
|
|
|
|
|
ruleMethod: 'parse_' + node.name,
|
|
|
|
|
resultVar: resultVar(context.resultIndex)
|
|
|
|
|
}
|
|
|
|
|
);
|
|
|
|
@ -713,18 +713,18 @@ PEG.compiler.emitter = function(ast) {
|
|
|
|
|
|
|
|
|
|
if (length === 0) {
|
|
|
|
|
return formatCode(
|
|
|
|
|
"${resultVar} = '';",
|
|
|
|
|
'${resultVar} = "";',
|
|
|
|
|
{ resultVar: resultVar(context.resultIndex) }
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var testCode = length === 1
|
|
|
|
|
? formatCode(
|
|
|
|
|
"input.charCodeAt(pos) === ${valueCharCode}",
|
|
|
|
|
'input.charCodeAt(pos) === ${valueCharCode}',
|
|
|
|
|
{ valueCharCode: node.value.charCodeAt(0) }
|
|
|
|
|
)
|
|
|
|
|
: formatCode(
|
|
|
|
|
"input.substr(pos, ${length}) === ${value|string}",
|
|
|
|
|
'input.substr(pos, ${length}) === ${value|string}',
|
|
|
|
|
{
|
|
|
|
|
value: node.value,
|
|
|
|
|
length: length
|
|
|
|
@ -732,15 +732,15 @@ PEG.compiler.emitter = function(ast) {
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
return formatCode(
|
|
|
|
|
"if (${testCode}) {",
|
|
|
|
|
" ${resultVar} = ${value|string};",
|
|
|
|
|
" pos += ${length};",
|
|
|
|
|
"} else {",
|
|
|
|
|
" ${resultVar} = null;",
|
|
|
|
|
" if (reportFailures === 0) {",
|
|
|
|
|
" matchFailed(${valueQuoted|string});",
|
|
|
|
|
" }",
|
|
|
|
|
"}",
|
|
|
|
|
'if (${testCode}) {',
|
|
|
|
|
' ${resultVar} = ${value|string};',
|
|
|
|
|
' pos += ${length};',
|
|
|
|
|
'} else {',
|
|
|
|
|
' ${resultVar} = null;',
|
|
|
|
|
' if (reportFailures === 0) {',
|
|
|
|
|
' matchFailed(${valueQuoted|string});',
|
|
|
|
|
' }',
|
|
|
|
|
'}',
|
|
|
|
|
{
|
|
|
|
|
testCode: testCode,
|
|
|
|
|
value: node.value,
|
|
|
|
@ -753,15 +753,15 @@ PEG.compiler.emitter = function(ast) {
|
|
|
|
|
|
|
|
|
|
any: function(node, context) {
|
|
|
|
|
return formatCode(
|
|
|
|
|
"if (input.length > pos) {",
|
|
|
|
|
" ${resultVar} = input.charAt(pos);",
|
|
|
|
|
" pos++;",
|
|
|
|
|
"} else {",
|
|
|
|
|
" ${resultVar} = null;",
|
|
|
|
|
" if (reportFailures === 0) {",
|
|
|
|
|
" matchFailed('any character');",
|
|
|
|
|
" }",
|
|
|
|
|
"}",
|
|
|
|
|
'if (input.length > pos) {',
|
|
|
|
|
' ${resultVar} = input.charAt(pos);',
|
|
|
|
|
' pos++;',
|
|
|
|
|
'} else {',
|
|
|
|
|
' ${resultVar} = null;',
|
|
|
|
|
' if (reportFailures === 0) {',
|
|
|
|
|
' matchFailed("any character");',
|
|
|
|
|
' }',
|
|
|
|
|
'}',
|
|
|
|
|
{ resultVar: resultVar(context.resultIndex) }
|
|
|
|
|
);
|
|
|
|
|
},
|
|
|
|
@ -770,34 +770,34 @@ PEG.compiler.emitter = function(ast) {
|
|
|
|
|
var regexp;
|
|
|
|
|
|
|
|
|
|
if (node.parts.length > 0) {
|
|
|
|
|
regexp = "/^["
|
|
|
|
|
+ (node.inverted ? "^" : "")
|
|
|
|
|
regexp = '/^['
|
|
|
|
|
+ (node.inverted ? '^' : '')
|
|
|
|
|
+ map(node.parts, function(part) {
|
|
|
|
|
return part instanceof Array
|
|
|
|
|
? quoteForRegexpClass(part[0])
|
|
|
|
|
+ "-"
|
|
|
|
|
+ '-'
|
|
|
|
|
+ quoteForRegexpClass(part[1])
|
|
|
|
|
: quoteForRegexpClass(part);
|
|
|
|
|
}).join("")
|
|
|
|
|
+ "]/";
|
|
|
|
|
}).join('')
|
|
|
|
|
+ ']/';
|
|
|
|
|
} else {
|
|
|
|
|
/*
|
|
|
|
|
* Stupid IE considers regexps /[]/ and /[^]/ syntactically invalid, so
|
|
|
|
|
* we translate them into euqivalents it can handle.
|
|
|
|
|
*/
|
|
|
|
|
regexp = node.inverted ? "/^[\\S\\s]/" : "/^(?!)/";
|
|
|
|
|
regexp = node.inverted ? '/^[\\S\\s]/' : '/^(?!)/';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return formatCode(
|
|
|
|
|
"if (${regexp}.test(input.charAt(pos))) {",
|
|
|
|
|
" ${resultVar} = input.charAt(pos);",
|
|
|
|
|
" pos++;",
|
|
|
|
|
"} else {",
|
|
|
|
|
" ${resultVar} = null;",
|
|
|
|
|
" if (reportFailures === 0) {",
|
|
|
|
|
" matchFailed(${rawText|string});",
|
|
|
|
|
" }",
|
|
|
|
|
"}",
|
|
|
|
|
'if (${regexp}.test(input.charAt(pos))) {',
|
|
|
|
|
' ${resultVar} = input.charAt(pos);',
|
|
|
|
|
' pos++;',
|
|
|
|
|
'} else {',
|
|
|
|
|
' ${resultVar} = null;',
|
|
|
|
|
' if (reportFailures === 0) {',
|
|
|
|
|
' matchFailed(${rawText|string});',
|
|
|
|
|
' }',
|
|
|
|
|
'}',
|
|
|
|
|
{
|
|
|
|
|
regexp: regexp,
|
|
|
|
|
rawText: node.rawText,
|
|
|
|
|