diff options
Diffstat (limited to 'cordova/node_modules/pegjs/lib/compiler')
13 files changed, 2586 insertions, 0 deletions
diff --git a/cordova/node_modules/pegjs/lib/compiler/asts.js b/cordova/node_modules/pegjs/lib/compiler/asts.js new file mode 100644 index 0000000..7dac649 --- /dev/null +++ b/cordova/node_modules/pegjs/lib/compiler/asts.js @@ -0,0 +1,65 @@ +"use strict"; + +var arrays = require("../utils/arrays"), + visitor = require("./visitor"); + +/* AST utilities. */ +var asts = { + findRule: function(ast, name) { + return arrays.find(ast.rules, function(r) { return r.name === name; }); + }, + + indexOfRule: function(ast, name) { + return arrays.indexOf(ast.rules, function(r) { return r.name === name; }); + }, + + alwaysConsumesOnSuccess: function(ast, node) { + function consumesTrue() { return true; } + function consumesFalse() { return false; } + + function consumesExpression(node) { + return consumes(node.expression); + } + + var consumes = visitor.build({ + rule: consumesExpression, + named: consumesExpression, + + choice: function(node) { + return arrays.every(node.alternatives, consumes); + }, + + action: consumesExpression, + + sequence: function(node) { + return arrays.some(node.elements, consumes); + }, + + labeled: consumesExpression, + text: consumesExpression, + simple_and: consumesFalse, + simple_not: consumesFalse, + optional: consumesFalse, + zero_or_more: consumesFalse, + one_or_more: consumesExpression, + group: consumesExpression, + semantic_and: consumesFalse, + semantic_not: consumesFalse, + + rule_ref: function(node) { + return consumes(asts.findRule(ast, node.name)); + }, + + literal: function(node) { + return node.value !== ""; + }, + + "class": consumesTrue, + any: consumesTrue + }); + + return consumes(node); + } +}; + +module.exports = asts; diff --git a/cordova/node_modules/pegjs/lib/compiler/index.js b/cordova/node_modules/pegjs/lib/compiler/index.js new file mode 100644 index 0000000..1248598 --- /dev/null +++ b/cordova/node_modules/pegjs/lib/compiler/index.js @@ -0,0 +1,73 @@ +"use strict"; + +var arrays = require("../utils/arrays"), + objects = require("../utils/objects"); + +var compiler = { + /* + * AST node visitor builder. Useful mainly for plugins which manipulate the + * AST. + */ + visitor: require("./visitor"), + + /* + * 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|. + */ + passes: { + check: { + reportUndefinedRules: require("./passes/report-undefined-rules"), + reportDuplicateRules: require("./passes/report-duplicate-rules"), + reportDuplicateLabels: require("./passes/report-duplicate-labels"), + reportInfiniteRecursion: require("./passes/report-infinite-recursion"), + reportInfiniteRepetition: require("./passes/report-infinite-repetition") + }, + transform: { + removeProxyRules: require("./passes/remove-proxy-rules") + }, + generate: { + generateBytecode: require("./passes/generate-bytecode"), + generateJS: require("./passes/generate-js") + } + }, + + /* + * 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, passes, options) { + options = options !== void 0 ? options : {}; + + var stage; + + options = objects.clone(options); + objects.defaults(options, { + allowedStartRules: [ast.rules[0].name], + cache: false, + dependencies: {}, + exportVar: null, + format: "bare", + optimize: "speed", + output: "parser", + trace: false + }); + + for (stage in passes) { + if (passes.hasOwnProperty(stage)) { + arrays.each(passes[stage], function(p) { p(ast, options); }); + } + } + + switch (options.output) { + case "parser": return eval(ast.code); + case "source": return ast.code; + } + } +}; + +module.exports = compiler; diff --git a/cordova/node_modules/pegjs/lib/compiler/js.js b/cordova/node_modules/pegjs/lib/compiler/js.js new file mode 100644 index 0000000..3da25a4 --- /dev/null +++ b/cordova/node_modules/pegjs/lib/compiler/js.js @@ -0,0 +1,58 @@ +"use strict"; + +function hex(ch) { return ch.charCodeAt(0).toString(16).toUpperCase(); } + +/* JavaScript code generation helpers. */ +var js = { + stringEscape: function(s) { + /* + * ECMA-262, 5th ed., 7.8.4: All characters may appear literally in a string + * literal except for the closing quote character, backslash, carriage + * return, line separator, paragraph separator, and line feed. Any character + * may appear in the form of an escape sequence. + * + * For portability, we also escape all control and non-ASCII characters. + * Note that the "\v" escape sequence is not used because IE does not like + * it. + */ + return s + .replace(/\\/g, '\\\\') // backslash + .replace(/"/g, '\\"') // closing double quote + .replace(/\0/g, '\\0') // null + .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-\x0F]/g, function(ch) { return '\\x0' + hex(ch); }) + .replace(/[\x10-\x1F\x7F-\xFF]/g, function(ch) { return '\\x' + hex(ch); }) + .replace(/[\u0100-\u0FFF]/g, function(ch) { return '\\u0' + hex(ch); }) + .replace(/[\u1000-\uFFFF]/g, function(ch) { return '\\u' + hex(ch); }); + }, + + regexpClassEscape: function(s) { + /* + * Based on ECMA-262, 5th ed., 7.8.5 & 15.10.1. + * + * For portability, we also escape all control and non-ASCII characters. + */ + return s + .replace(/\\/g, '\\\\') // backslash + .replace(/\//g, '\\/') // closing slash + .replace(/\]/g, '\\]') // closing bracket + .replace(/\^/g, '\\^') // caret + .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(/[\x00-\x0F]/g, function(ch) { return '\\x0' + hex(ch); }) + .replace(/[\x10-\x1F\x7F-\xFF]/g, function(ch) { return '\\x' + hex(ch); }) + .replace(/[\u0100-\u0FFF]/g, function(ch) { return '\\u0' + hex(ch); }) + .replace(/[\u1000-\uFFFF]/g, function(ch) { return '\\u' + hex(ch); }); + } +}; + +module.exports = js; diff --git a/cordova/node_modules/pegjs/lib/compiler/opcodes.js b/cordova/node_modules/pegjs/lib/compiler/opcodes.js new file mode 100644 index 0000000..4c52008 --- /dev/null +++ b/cordova/node_modules/pegjs/lib/compiler/opcodes.js @@ -0,0 +1,54 @@ +"use strict"; + +/* Bytecode instruction opcodes. */ +var opcodes = { + /* Stack Manipulation */ + + PUSH: 0, // PUSH c + PUSH_UNDEFINED: 1, // PUSH_UNDEFINED + PUSH_NULL: 2, // PUSH_NULL + PUSH_FAILED: 3, // PUSH_FAILED + PUSH_EMPTY_ARRAY: 4, // PUSH_EMPTY_ARRAY + PUSH_CURR_POS: 5, // PUSH_CURR_POS + POP: 6, // POP + POP_CURR_POS: 7, // POP_CURR_POS + POP_N: 8, // POP_N n + NIP: 9, // NIP + APPEND: 10, // APPEND + WRAP: 11, // WRAP n + TEXT: 12, // TEXT + + /* Conditions and Loops */ + + IF: 13, // IF t, f + IF_ERROR: 14, // IF_ERROR t, f + IF_NOT_ERROR: 15, // IF_NOT_ERROR t, f + WHILE_NOT_ERROR: 16, // WHILE_NOT_ERROR b + + /* Matching */ + + MATCH_ANY: 17, // MATCH_ANY a, f, ... + MATCH_STRING: 18, // MATCH_STRING s, a, f, ... + MATCH_STRING_IC: 19, // MATCH_STRING_IC s, a, f, ... + MATCH_REGEXP: 20, // MATCH_REGEXP r, a, f, ... + ACCEPT_N: 21, // ACCEPT_N n + ACCEPT_STRING: 22, // ACCEPT_STRING s + FAIL: 23, // FAIL e + + /* Calls */ + + LOAD_SAVED_POS: 24, // LOAD_SAVED_POS p + UPDATE_SAVED_POS: 25, // UPDATE_SAVED_POS + CALL: 26, // CALL f, n, pc, p1, p2, ..., pN + + /* Rules */ + + RULE: 27, // RULE r + + /* Failure Reporting */ + + SILENT_FAILS_ON: 28, // SILENT_FAILS_ON + SILENT_FAILS_OFF: 29 // SILENT_FAILS_OFF +}; + +module.exports = opcodes; diff --git a/cordova/node_modules/pegjs/lib/compiler/passes/generate-bytecode.js b/cordova/node_modules/pegjs/lib/compiler/passes/generate-bytecode.js new file mode 100644 index 0000000..60c81a9 --- /dev/null +++ b/cordova/node_modules/pegjs/lib/compiler/passes/generate-bytecode.js @@ -0,0 +1,631 @@ +"use strict"; + +var arrays = require("../../utils/arrays"), + objects = require("../../utils/objects"), + asts = require("../asts"), + visitor = require("../visitor"), + op = require("../opcodes"), + js = require("../js"); + +/* Generates bytecode. + * + * Instructions + * ============ + * + * Stack Manipulation + * ------------------ + * + * [0] PUSH c + * + * stack.push(consts[c]); + * + * [1] PUSH_UNDEFINED + * + * stack.push(undefined); + * + * [2] PUSH_NULL + * + * stack.push(null); + * + * [3] PUSH_FAILED + * + * stack.push(FAILED); + * + * [4] PUSH_EMPTY_ARRAY + * + * stack.push([]); + * + * [5] PUSH_CURR_POS + * + * stack.push(currPos); + * + * [6] POP + * + * stack.pop(); + * + * [7] POP_CURR_POS + * + * currPos = stack.pop(); + * + * [8] POP_N n + * + * stack.pop(n); + * + * [9] NIP + * + * value = stack.pop(); + * stack.pop(); + * stack.push(value); + * + * [10] APPEND + * + * value = stack.pop(); + * array = stack.pop(); + * array.push(value); + * stack.push(array); + * + * [11] WRAP n + * + * stack.push(stack.pop(n)); + * + * [12] TEXT + * + * stack.push(input.substring(stack.pop(), currPos)); + * + * Conditions and Loops + * -------------------- + * + * [13] IF t, f + * + * if (stack.top()) { + * interpret(ip + 3, ip + 3 + t); + * } else { + * interpret(ip + 3 + t, ip + 3 + t + f); + * } + * + * [14] IF_ERROR t, f + * + * if (stack.top() === FAILED) { + * interpret(ip + 3, ip + 3 + t); + * } else { + * interpret(ip + 3 + t, ip + 3 + t + f); + * } + * + * [15] IF_NOT_ERROR t, f + * + * if (stack.top() !== FAILED) { + * interpret(ip + 3, ip + 3 + t); + * } else { + * interpret(ip + 3 + t, ip + 3 + t + f); + * } + * + * [16] WHILE_NOT_ERROR b + * + * while(stack.top() !== FAILED) { + * interpret(ip + 2, ip + 2 + b); + * } + * + * Matching + * -------- + * + * [17] MATCH_ANY a, f, ... + * + * if (input.length > currPos) { + * interpret(ip + 3, ip + 3 + a); + * } else { + * interpret(ip + 3 + a, ip + 3 + a + f); + * } + * + * [18] MATCH_STRING s, a, f, ... + * + * if (input.substr(currPos, consts[s].length) === consts[s]) { + * interpret(ip + 4, ip + 4 + a); + * } else { + * interpret(ip + 4 + a, ip + 4 + a + f); + * } + * + * [19] MATCH_STRING_IC s, a, f, ... + * + * if (input.substr(currPos, consts[s].length).toLowerCase() === consts[s]) { + * interpret(ip + 4, ip + 4 + a); + * } else { + * interpret(ip + 4 + a, ip + 4 + a + f); + * } + * + * [20] MATCH_REGEXP r, a, f, ... + * + * if (consts[r].test(input.charAt(currPos))) { + * interpret(ip + 4, ip + 4 + a); + * } else { + * interpret(ip + 4 + a, ip + 4 + a + f); + * } + * + * [21] ACCEPT_N n + * + * stack.push(input.substring(currPos, n)); + * currPos += n; + * + * [22] ACCEPT_STRING s + * + * stack.push(consts[s]); + * currPos += consts[s].length; + * + * [23] FAIL e + * + * stack.push(FAILED); + * fail(consts[e]); + * + * Calls + * ----- + * + * [24] LOAD_SAVED_POS p + * + * savedPos = stack[p]; + * + * [25] UPDATE_SAVED_POS + * + * savedPos = currPos; + * + * [26] CALL f, n, pc, p1, p2, ..., pN + * + * value = consts[f](stack[p1], ..., stack[pN]); + * stack.pop(n); + * stack.push(value); + * + * Rules + * ----- + * + * [27] RULE r + * + * stack.push(parseRule(r)); + * + * Failure Reporting + * ----------------- + * + * [28] SILENT_FAILS_ON + * + * silentFails++; + * + * [29] SILENT_FAILS_OFF + * + * silentFails--; + */ +function generateBytecode(ast) { + var consts = []; + + function addConst(value) { + var index = arrays.indexOf(consts, value); + + return index === -1 ? consts.push(value) - 1 : index; + } + + function addFunctionConst(params, code) { + return addConst( + "function(" + params.join(", ") + ") {" + code + "}" + ); + } + + function buildSequence() { + return Array.prototype.concat.apply([], arguments); + } + + function buildCondition(condCode, thenCode, elseCode) { + return condCode.concat( + [thenCode.length, elseCode.length], + thenCode, + elseCode + ); + } + + function buildLoop(condCode, bodyCode) { + return condCode.concat([bodyCode.length], bodyCode); + } + + function buildCall(functionIndex, delta, env, sp) { + var params = arrays.map(objects.values(env), function(p) { return sp - p; }); + + return [op.CALL, functionIndex, delta, params.length].concat(params); + } + + function buildSimplePredicate(expression, negative, context) { + return buildSequence( + [op.PUSH_CURR_POS], + [op.SILENT_FAILS_ON], + generate(expression, { + sp: context.sp + 1, + env: objects.clone(context.env), + action: null + }), + [op.SILENT_FAILS_OFF], + buildCondition( + [negative ? op.IF_ERROR : op.IF_NOT_ERROR], + buildSequence( + [op.POP], + [negative ? op.POP : op.POP_CURR_POS], + [op.PUSH_UNDEFINED] + ), + buildSequence( + [op.POP], + [negative ? op.POP_CURR_POS : op.POP], + [op.PUSH_FAILED] + ) + ) + ); + } + + function buildSemanticPredicate(code, negative, context) { + var functionIndex = addFunctionConst(objects.keys(context.env), code); + + return buildSequence( + [op.UPDATE_SAVED_POS], + buildCall(functionIndex, 0, context.env, context.sp), + buildCondition( + [op.IF], + buildSequence( + [op.POP], + negative ? [op.PUSH_FAILED] : [op.PUSH_UNDEFINED] + ), + buildSequence( + [op.POP], + negative ? [op.PUSH_UNDEFINED] : [op.PUSH_FAILED] + ) + ) + ); + } + + function buildAppendLoop(expressionCode) { + return buildLoop( + [op.WHILE_NOT_ERROR], + buildSequence([op.APPEND], expressionCode) + ); + } + + var generate = visitor.build({ + grammar: function(node) { + arrays.each(node.rules, generate); + + node.consts = consts; + }, + + rule: function(node) { + node.bytecode = generate(node.expression, { + sp: -1, // stack pointer + env: { }, // mapping of label names to stack positions + action: null // action nodes pass themselves to children here + }); + }, + + named: function(node, context) { + var nameIndex = addConst( + 'peg$otherExpectation("' + js.stringEscape(node.name) + '")' + ); + + /* + * The code generated below is slightly suboptimal because |FAIL| pushes + * to the stack, so we need to stick a |POP| in front of it. We lack a + * dedicated instruction that would just report the failure and not touch + * the stack. + */ + return buildSequence( + [op.SILENT_FAILS_ON], + generate(node.expression, context), + [op.SILENT_FAILS_OFF], + buildCondition([op.IF_ERROR], [op.FAIL, nameIndex], []) + ); + }, + + choice: function(node, context) { + function buildAlternativesCode(alternatives, context) { + return buildSequence( + generate(alternatives[0], { + sp: context.sp, + env: objects.clone(context.env), + action: null + }), + alternatives.length > 1 + ? buildCondition( + [op.IF_ERROR], + buildSequence( + [op.POP], + buildAlternativesCode(alternatives.slice(1), context) + ), + [] + ) + : [] + ); + } + + return buildAlternativesCode(node.alternatives, context); + }, + + action: function(node, context) { + var env = objects.clone(context.env), + emitCall = node.expression.type !== "sequence" + || node.expression.elements.length === 0, + expressionCode = generate(node.expression, { + sp: context.sp + (emitCall ? 1 : 0), + env: env, + action: node + }), + functionIndex = addFunctionConst(objects.keys(env), node.code); + + return emitCall + ? buildSequence( + [op.PUSH_CURR_POS], + expressionCode, + buildCondition( + [op.IF_NOT_ERROR], + buildSequence( + [op.LOAD_SAVED_POS, 1], + buildCall(functionIndex, 1, env, context.sp + 2) + ), + [] + ), + [op.NIP] + ) + : expressionCode; + }, + + sequence: function(node, context) { + function buildElementsCode(elements, context) { + var processedCount, functionIndex; + + if (elements.length > 0) { + processedCount = node.elements.length - elements.slice(1).length; + + return buildSequence( + generate(elements[0], { + sp: context.sp, + env: context.env, + action: null + }), + buildCondition( + [op.IF_NOT_ERROR], + buildElementsCode(elements.slice(1), { + sp: context.sp + 1, + env: context.env, + action: context.action + }), + buildSequence( + processedCount > 1 ? [op.POP_N, processedCount] : [op.POP], + [op.POP_CURR_POS], + [op.PUSH_FAILED] + ) + ) + ); + } else { + if (context.action) { + functionIndex = addFunctionConst( + objects.keys(context.env), + context.action.code + ); + + return buildSequence( + [op.LOAD_SAVED_POS, node.elements.length], + buildCall( + functionIndex, + node.elements.length, + context.env, + context.sp + ), + [op.NIP] + ); + } else { + return buildSequence([op.WRAP, node.elements.length], [op.NIP]); + } + } + } + + return buildSequence( + [op.PUSH_CURR_POS], + buildElementsCode(node.elements, { + sp: context.sp + 1, + env: context.env, + action: context.action + }) + ); + }, + + labeled: function(node, context) { + var env = objects.clone(context.env); + + context.env[node.label] = context.sp + 1; + + return generate(node.expression, { + sp: context.sp, + env: env, + action: null + }); + }, + + text: function(node, context) { + return buildSequence( + [op.PUSH_CURR_POS], + generate(node.expression, { + sp: context.sp + 1, + env: objects.clone(context.env), + action: null + }), + buildCondition( + [op.IF_NOT_ERROR], + buildSequence([op.POP], [op.TEXT]), + [op.NIP] + ) + ); + }, + + simple_and: function(node, context) { + return buildSimplePredicate(node.expression, false, context); + }, + + simple_not: function(node, context) { + return buildSimplePredicate(node.expression, true, context); + }, + + optional: function(node, context) { + return buildSequence( + generate(node.expression, { + sp: context.sp, + env: objects.clone(context.env), + action: null + }), + buildCondition( + [op.IF_ERROR], + buildSequence([op.POP], [op.PUSH_NULL]), + [] + ) + ); + }, + + zero_or_more: function(node, context) { + var expressionCode = generate(node.expression, { + sp: context.sp + 1, + env: objects.clone(context.env), + action: null + }); + + return buildSequence( + [op.PUSH_EMPTY_ARRAY], + expressionCode, + buildAppendLoop(expressionCode), + [op.POP] + ); + }, + + one_or_more: function(node, context) { + var expressionCode = generate(node.expression, { + sp: context.sp + 1, + env: objects.clone(context.env), + action: null + }); + + return buildSequence( + [op.PUSH_EMPTY_ARRAY], + expressionCode, + buildCondition( + [op.IF_NOT_ERROR], + buildSequence(buildAppendLoop(expressionCode), [op.POP]), + buildSequence([op.POP], [op.POP], [op.PUSH_FAILED]) + ) + ); + }, + + group: function(node, context) { + return generate(node.expression, { + sp: context.sp, + env: objects.clone(context.env), + action: null + }); + }, + + semantic_and: function(node, context) { + return buildSemanticPredicate(node.code, false, context); + }, + + semantic_not: function(node, context) { + return buildSemanticPredicate(node.code, true, context); + }, + + rule_ref: function(node) { + return [op.RULE, asts.indexOfRule(ast, node.name)]; + }, + + literal: function(node) { + var stringIndex, expectedIndex; + + if (node.value.length > 0) { + stringIndex = addConst('"' + + js.stringEscape( + node.ignoreCase ? node.value.toLowerCase() : node.value + ) + + '"' + ); + expectedIndex = addConst( + 'peg$literalExpectation(' + + '"' + js.stringEscape(node.value) + '", ' + + node.ignoreCase + + ')' + ); + + /* + * For case-sensitive strings the value must match the beginning of the + * remaining input exactly. As a result, we can use |ACCEPT_STRING| and + * save one |substr| call that would be needed if we used |ACCEPT_N|. + */ + return buildCondition( + node.ignoreCase + ? [op.MATCH_STRING_IC, stringIndex] + : [op.MATCH_STRING, stringIndex], + node.ignoreCase + ? [op.ACCEPT_N, node.value.length] + : [op.ACCEPT_STRING, stringIndex], + [op.FAIL, expectedIndex] + ); + } else { + stringIndex = addConst('""'); + + return [op.PUSH, stringIndex]; + } + }, + + "class": function(node) { + var regexp, parts, regexpIndex, expectedIndex; + + if (node.parts.length > 0) { + regexp = '/^[' + + (node.inverted ? '^' : '') + + arrays.map(node.parts, function(part) { + return part instanceof Array + ? js.regexpClassEscape(part[0]) + + '-' + + js.regexpClassEscape(part[1]) + : js.regexpClassEscape(part); + }).join('') + + ']/' + (node.ignoreCase ? 'i' : ''); + } else { + /* + * IE considers regexps /[]/ and /[^]/ as syntactically invalid, so we + * translate them into equivalents it can handle. + */ + regexp = node.inverted ? '/^[\\S\\s]/' : '/^(?!)/'; + } + + parts = '[' + + arrays.map(node.parts, function(part) { + return part instanceof Array + ? '["' + js.stringEscape(part[0]) + '", "' + js.stringEscape(part[1]) + '"]' + : '"' + js.stringEscape(part) + '"'; + }).join(', ') + + ']'; + + regexpIndex = addConst(regexp); + expectedIndex = addConst( + 'peg$classExpectation(' + + parts + ', ' + + node.inverted + ', ' + + node.ignoreCase + + ')' + ); + + return buildCondition( + [op.MATCH_REGEXP, regexpIndex], + [op.ACCEPT_N, 1], + [op.FAIL, expectedIndex] + ); + }, + + any: function() { + var expectedIndex = addConst('peg$anyExpectation()'); + + return buildCondition( + [op.MATCH_ANY], + [op.ACCEPT_N, 1], + [op.FAIL, expectedIndex] + ); + } + }); + + generate(ast); +} + +module.exports = generateBytecode; diff --git a/cordova/node_modules/pegjs/lib/compiler/passes/generate-js.js b/cordova/node_modules/pegjs/lib/compiler/passes/generate-js.js new file mode 100644 index 0000000..c579ac9 --- /dev/null +++ b/cordova/node_modules/pegjs/lib/compiler/passes/generate-js.js @@ -0,0 +1,1394 @@ +"use strict"; + +var arrays = require("../../utils/arrays"), + objects = require("../../utils/objects"), + asts = require("../asts"), + op = require("../opcodes"), + js = require("../js"); + +/* Generates parser JavaScript code. */ +function generateJS(ast, options) { + /* These only indent non-empty lines to avoid trailing whitespace. */ + function indent2(code) { return code.replace(/^(.+)$/gm, ' $1'); } + function indent6(code) { return code.replace(/^(.+)$/gm, ' $1'); } + function indent10(code) { return code.replace(/^(.+)$/gm, ' $1'); } + + function generateTables() { + if (options.optimize === "size") { + return [ + 'peg$consts = [', + indent2(ast.consts.join(',\n')), + '],', + '', + 'peg$bytecode = [', + indent2(arrays.map(ast.rules, function(rule) { + return 'peg$decode("' + + js.stringEscape(arrays.map( + rule.bytecode, + function(b) { return String.fromCharCode(b + 32); } + ).join('')) + + '")'; + }).join(',\n')), + '],' + ].join('\n'); + } else { + return arrays.map( + ast.consts, + function(c, i) { return 'peg$c' + i + ' = ' + c + ','; } + ).join('\n'); + } + } + + function generateRuleHeader(ruleNameCode, ruleIndexCode) { + var parts = []; + + parts.push(''); + + if (options.trace) { + parts.push([ + 'peg$tracer.trace({', + ' type: "rule.enter",', + ' rule: ' + ruleNameCode + ',', + ' location: peg$computeLocation(startPos, startPos)', + '});', + '' + ].join('\n')); + } + + if (options.cache) { + parts.push([ + 'var key = peg$currPos * ' + ast.rules.length + ' + ' + ruleIndexCode + ',', + ' cached = peg$resultsCache[key];', + '', + 'if (cached) {', + ' peg$currPos = cached.nextPos;', + '' + ].join('\n')); + + if (options.trace) { + parts.push([ + 'if (cached.result !== peg$FAILED) {', + ' peg$tracer.trace({', + ' type: "rule.match",', + ' rule: ' + ruleNameCode + ',', + ' result: cached.result,', + ' location: peg$computeLocation(startPos, peg$currPos)', + ' });', + '} else {', + ' peg$tracer.trace({', + ' type: "rule.fail",', + ' rule: ' + ruleNameCode + ',', + ' location: peg$computeLocation(startPos, startPos)', + ' });', + '}', + '' + ].join('\n')); + } + + parts.push([ + ' return cached.result;', + '}', + '' + ].join('\n')); + } + + return parts.join('\n'); + } + + function generateRuleFooter(ruleNameCode, resultCode) { + var parts = []; + + if (options.cache) { + parts.push([ + '', + 'peg$resultsCache[key] = { nextPos: peg$currPos, result: ' + resultCode + ' };' + ].join('\n')); + } + + if (options.trace) { + parts.push([ + '', + 'if (' + resultCode + ' !== peg$FAILED) {', + ' peg$tracer.trace({', + ' type: "rule.match",', + ' rule: ' + ruleNameCode + ',', + ' result: ' + resultCode + ',', + ' location: peg$computeLocation(startPos, peg$currPos)', + ' });', + '} else {', + ' peg$tracer.trace({', + ' type: "rule.fail",', + ' rule: ' + ruleNameCode + ',', + ' location: peg$computeLocation(startPos, startPos)', + ' });', + '}' + ].join('\n')); + } + + parts.push([ + '', + 'return ' + resultCode + ';' + ].join('\n')); + + return parts.join('\n'); + } + + function generateInterpreter() { + var parts = []; + + function generateCondition(cond, argsLength) { + var baseLength = argsLength + 3, + thenLengthCode = 'bc[ip + ' + (baseLength - 2) + ']', + elseLengthCode = 'bc[ip + ' + (baseLength - 1) + ']'; + + return [ + 'ends.push(end);', + 'ips.push(ip + ' + baseLength + ' + ' + thenLengthCode + ' + ' + elseLengthCode + ');', + '', + 'if (' + cond + ') {', + ' end = ip + ' + baseLength + ' + ' + thenLengthCode + ';', + ' ip += ' + baseLength + ';', + '} else {', + ' end = ip + ' + baseLength + ' + ' + thenLengthCode + ' + ' + elseLengthCode + ';', + ' ip += ' + baseLength + ' + ' + thenLengthCode + ';', + '}', + '', + 'break;' + ].join('\n'); + } + + function generateLoop(cond) { + var baseLength = 2, + bodyLengthCode = 'bc[ip + ' + (baseLength - 1) + ']'; + + return [ + 'if (' + cond + ') {', + ' ends.push(end);', + ' ips.push(ip);', + '', + ' end = ip + ' + baseLength + ' + ' + bodyLengthCode + ';', + ' ip += ' + baseLength + ';', + '} else {', + ' ip += ' + baseLength + ' + ' + bodyLengthCode + ';', + '}', + '', + 'break;' + ].join('\n'); + } + + function generateCall() { + var baseLength = 4, + paramsLengthCode = 'bc[ip + ' + (baseLength - 1) + ']'; + + return [ + 'params = bc.slice(ip + ' + baseLength + ', ip + ' + baseLength + ' + ' + paramsLengthCode + ');', + 'for (i = 0; i < ' + paramsLengthCode + '; i++) {', + ' params[i] = stack[stack.length - 1 - params[i]];', + '}', + '', + 'stack.splice(', + ' stack.length - bc[ip + 2],', + ' bc[ip + 2],', + ' peg$consts[bc[ip + 1]].apply(null, params)', + ');', + '', + 'ip += ' + baseLength + ' + ' + paramsLengthCode + ';', + 'break;' + ].join('\n'); + } + + parts.push([ + 'function peg$decode(s) {', + ' var bc = new Array(s.length), i;', + '', + ' for (i = 0; i < s.length; i++) {', + ' bc[i] = s.charCodeAt(i) - 32;', + ' }', + '', + ' return bc;', + '}', + '', + 'function peg$parseRule(index) {' + ].join('\n')); + + if (options.trace) { + parts.push([ + ' var bc = peg$bytecode[index],', + ' ip = 0,', + ' ips = [],', + ' end = bc.length,', + ' ends = [],', + ' stack = [],', + ' startPos = peg$currPos,', + ' params, i;' + ].join('\n')); + } else { + parts.push([ + ' var bc = peg$bytecode[index],', + ' ip = 0,', + ' ips = [],', + ' end = bc.length,', + ' ends = [],', + ' stack = [],', + ' params, i;' + ].join('\n')); + } + + parts.push(indent2(generateRuleHeader('peg$ruleNames[index]', 'index'))); + + parts.push([ + /* + * The point of the outer loop and the |ips| & |ends| stacks is to avoid + * recursive calls for interpreting parts of bytecode. In other words, we + * implement the |interpret| operation of the abstract machine without + * function calls. Such calls would likely slow the parser down and more + * importantly cause stack overflows for complex grammars. + */ + ' while (true) {', + ' while (ip < end) {', + ' switch (bc[ip]) {', + ' case ' + op.PUSH + ':', // PUSH c + ' stack.push(peg$consts[bc[ip + 1]]);', + ' ip += 2;', + ' break;', + '', + ' case ' + op.PUSH_UNDEFINED + ':', // PUSH_UNDEFINED + ' stack.push(void 0);', + ' ip++;', + ' break;', + '', + ' case ' + op.PUSH_NULL + ':', // PUSH_NULL + ' stack.push(null);', + ' ip++;', + ' break;', + '', + ' case ' + op.PUSH_FAILED + ':', // PUSH_FAILED + ' stack.push(peg$FAILED);', + ' ip++;', + ' break;', + '', + ' case ' + op.PUSH_EMPTY_ARRAY + ':', // PUSH_EMPTY_ARRAY + ' stack.push([]);', + ' ip++;', + ' break;', + '', + ' case ' + op.PUSH_CURR_POS + ':', // PUSH_CURR_POS + ' stack.push(peg$currPos);', + ' ip++;', + ' break;', + '', + ' case ' + op.POP + ':', // POP + ' stack.pop();', + ' ip++;', + ' break;', + '', + ' case ' + op.POP_CURR_POS + ':', // POP_CURR_POS + ' peg$currPos = stack.pop();', + ' ip++;', + ' break;', + '', + ' case ' + op.POP_N + ':', // POP_N n + ' stack.length -= bc[ip + 1];', + ' ip += 2;', + ' break;', + '', + ' case ' + op.NIP + ':', // NIP + ' stack.splice(-2, 1);', + ' ip++;', + ' break;', + '', + ' case ' + op.APPEND + ':', // APPEND + ' stack[stack.length - 2].push(stack.pop());', + ' ip++;', + ' break;', + '', + ' case ' + op.WRAP + ':', // WRAP n + ' stack.push(stack.splice(stack.length - bc[ip + 1], bc[ip + 1]));', + ' ip += 2;', + ' break;', + '', + ' case ' + op.TEXT + ':', // TEXT + ' stack.push(input.substring(stack.pop(), peg$currPos));', + ' ip++;', + ' break;', + '', + ' case ' + op.IF + ':', // IF t, f + indent10(generateCondition('stack[stack.length - 1]', 0)), + '', + ' case ' + op.IF_ERROR + ':', // IF_ERROR t, f + indent10(generateCondition( + 'stack[stack.length - 1] === peg$FAILED', + 0 + )), + '', + ' case ' + op.IF_NOT_ERROR + ':', // IF_NOT_ERROR t, f + indent10( + generateCondition('stack[stack.length - 1] !== peg$FAILED', + 0 + )), + '', + ' case ' + op.WHILE_NOT_ERROR + ':', // WHILE_NOT_ERROR b + indent10(generateLoop('stack[stack.length - 1] !== peg$FAILED')), + '', + ' case ' + op.MATCH_ANY + ':', // MATCH_ANY a, f, ... + indent10(generateCondition('input.length > peg$currPos', 0)), + '', + ' case ' + op.MATCH_STRING + ':', // MATCH_STRING s, a, f, ... + indent10(generateCondition( + 'input.substr(peg$currPos, peg$consts[bc[ip + 1]].length) === peg$consts[bc[ip + 1]]', + 1 + )), + '', + ' case ' + op.MATCH_STRING_IC + ':', // MATCH_STRING_IC s, a, f, ... + indent10(generateCondition( + 'input.substr(peg$currPos, peg$consts[bc[ip + 1]].length).toLowerCase() === peg$consts[bc[ip + 1]]', + 1 + )), + '', + ' case ' + op.MATCH_REGEXP + ':', // MATCH_REGEXP r, a, f, ... + indent10(generateCondition( + 'peg$consts[bc[ip + 1]].test(input.charAt(peg$currPos))', + 1 + )), + '', + ' case ' + op.ACCEPT_N + ':', // ACCEPT_N n + ' stack.push(input.substr(peg$currPos, bc[ip + 1]));', + ' peg$currPos += bc[ip + 1];', + ' ip += 2;', + ' break;', + '', + ' case ' + op.ACCEPT_STRING + ':', // ACCEPT_STRING s + ' stack.push(peg$consts[bc[ip + 1]]);', + ' peg$currPos += peg$consts[bc[ip + 1]].length;', + ' ip += 2;', + ' break;', + '', + ' case ' + op.FAIL + ':', // FAIL e + ' stack.push(peg$FAILED);', + ' if (peg$silentFails === 0) {', + ' peg$fail(peg$consts[bc[ip + 1]]);', + ' }', + ' ip += 2;', + ' break;', + '', + ' case ' + op.LOAD_SAVED_POS + ':', // LOAD_SAVED_POS p + ' peg$savedPos = stack[stack.length - 1 - bc[ip + 1]];', + ' ip += 2;', + ' break;', + '', + ' case ' + op.UPDATE_SAVED_POS + ':', // UPDATE_SAVED_POS + ' peg$savedPos = peg$currPos;', + ' ip++;', + ' break;', + '', + ' case ' + op.CALL + ':', // CALL f, n, pc, p1, p2, ..., pN + indent10(generateCall()), + '', + ' case ' + op.RULE + ':', // RULE r + ' stack.push(peg$parseRule(bc[ip + 1]));', + ' ip += 2;', + ' break;', + '', + ' case ' + op.SILENT_FAILS_ON + ':', // SILENT_FAILS_ON + ' peg$silentFails++;', + ' ip++;', + ' break;', + '', + ' case ' + op.SILENT_FAILS_OFF + ':', // SILENT_FAILS_OFF + ' peg$silentFails--;', + ' ip++;', + ' break;', + '', + ' default:', + ' throw new Error("Invalid opcode: " + bc[ip] + ".");', + ' }', + ' }', + '', + ' if (ends.length > 0) {', + ' end = ends.pop();', + ' ip = ips.pop();', + ' } else {', + ' break;', + ' }', + ' }' + ].join('\n')); + + parts.push(indent2(generateRuleFooter('peg$ruleNames[index]', 'stack[0]'))); + parts.push('}'); + + return parts.join('\n'); + } + + function generateRuleFunction(rule) { + var parts = [], code; + + function c(i) { return "peg$c" + i; } // |consts[i]| of the abstract machine + function s(i) { return "s" + i; } // |stack[i]| of the abstract machine + + var stack = { + sp: -1, + maxSp: -1, + + push: function(exprCode) { + var code = s(++this.sp) + ' = ' + exprCode + ';'; + + if (this.sp > this.maxSp) { this.maxSp = this.sp; } + + return code; + }, + + pop: function(n) { + var values; + + if (n === void 0) { + return s(this.sp--); + } else { + values = arrays.map(arrays.range(this.sp - n + 1, this.sp + 1), s); + this.sp -= n; + + return values; + } + }, + + top: function() { + return s(this.sp); + }, + + index: function(i) { + return s(this.sp - i); + } + }; + + function compile(bc) { + var ip = 0, + end = bc.length, + parts = [], + value; + + function compileCondition(cond, argCount) { + var baseLength = argCount + 3, + thenLength = bc[ip + baseLength - 2], + elseLength = bc[ip + baseLength - 1], + baseSp = stack.sp, + thenCode, elseCode, thenSp, elseSp; + + ip += baseLength; + thenCode = compile(bc.slice(ip, ip + thenLength)); + thenSp = stack.sp; + ip += thenLength; + + if (elseLength > 0) { + stack.sp = baseSp; + elseCode = compile(bc.slice(ip, ip + elseLength)); + elseSp = stack.sp; + ip += elseLength; + + if (thenSp !== elseSp) { + throw new Error( + "Branches of a condition must move the stack pointer in the same way." + ); + } + } + + parts.push('if (' + cond + ') {'); + parts.push(indent2(thenCode)); + if (elseLength > 0) { + parts.push('} else {'); + parts.push(indent2(elseCode)); + } + parts.push('}'); + } + + function compileLoop(cond) { + var baseLength = 2, + bodyLength = bc[ip + baseLength - 1], + baseSp = stack.sp, + bodyCode, bodySp; + + ip += baseLength; + bodyCode = compile(bc.slice(ip, ip + bodyLength)); + bodySp = stack.sp; + ip += bodyLength; + + if (bodySp !== baseSp) { + throw new Error("Body of a loop can't move the stack pointer."); + } + + parts.push('while (' + cond + ') {'); + parts.push(indent2(bodyCode)); + parts.push('}'); + } + + function compileCall() { + var baseLength = 4, + paramsLength = bc[ip + baseLength - 1]; + + var value = c(bc[ip + 1]) + '(' + + arrays.map( + bc.slice(ip + baseLength, ip + baseLength + paramsLength), + function(p) { return stack.index(p); } + ).join(', ') + + ')'; + stack.pop(bc[ip + 2]); + parts.push(stack.push(value)); + ip += baseLength + paramsLength; + } + + while (ip < end) { + switch (bc[ip]) { + case op.PUSH: // PUSH c + parts.push(stack.push(c(bc[ip + 1]))); + ip += 2; + break; + + case op.PUSH_CURR_POS: // PUSH_CURR_POS + parts.push(stack.push('peg$currPos')); + ip++; + break; + + case op.PUSH_UNDEFINED: // PUSH_UNDEFINED + parts.push(stack.push('void 0')); + ip++; + break; + + case op.PUSH_NULL: // PUSH_NULL + parts.push(stack.push('null')); + ip++; + break; + + case op.PUSH_FAILED: // PUSH_FAILED + parts.push(stack.push('peg$FAILED')); + ip++; + break; + + case op.PUSH_EMPTY_ARRAY: // PUSH_EMPTY_ARRAY + parts.push(stack.push('[]')); + ip++; + break; + + case op.POP: // POP + stack.pop(); + ip++; + break; + + case op.POP_CURR_POS: // POP_CURR_POS + parts.push('peg$currPos = ' + stack.pop() + ';'); + ip++; + break; + + case op.POP_N: // POP_N n + stack.pop(bc[ip + 1]); + ip += 2; + break; + + case op.NIP: // NIP + value = stack.pop(); + stack.pop(); + parts.push(stack.push(value)); + ip++; + break; + + case op.APPEND: // APPEND + value = stack.pop(); + parts.push(stack.top() + '.push(' + value + ');'); + ip++; + break; + + case op.WRAP: // WRAP n + parts.push( + stack.push('[' + stack.pop(bc[ip + 1]).join(', ') + ']') + ); + ip += 2; + break; + + case op.TEXT: // TEXT + parts.push( + stack.push('input.substring(' + stack.pop() + ', peg$currPos)') + ); + ip++; + break; + + case op.IF: // IF t, f + compileCondition(stack.top(), 0); + break; + + case op.IF_ERROR: // IF_ERROR t, f + compileCondition(stack.top() + ' === peg$FAILED', 0); + break; + + case op.IF_NOT_ERROR: // IF_NOT_ERROR t, f + compileCondition(stack.top() + ' !== peg$FAILED', 0); + break; + + case op.WHILE_NOT_ERROR: // WHILE_NOT_ERROR b + compileLoop(stack.top() + ' !== peg$FAILED', 0); + break; + + case op.MATCH_ANY: // MATCH_ANY a, f, ... + compileCondition('input.length > peg$currPos', 0); + break; + + case op.MATCH_STRING: // MATCH_STRING s, a, f, ... + compileCondition( + eval(ast.consts[bc[ip + 1]]).length > 1 + ? 'input.substr(peg$currPos, ' + + eval(ast.consts[bc[ip + 1]]).length + + ') === ' + + c(bc[ip + 1]) + : 'input.charCodeAt(peg$currPos) === ' + + eval(ast.consts[bc[ip + 1]]).charCodeAt(0), + 1 + ); + break; + + case op.MATCH_STRING_IC: // MATCH_STRING_IC s, a, f, ... + compileCondition( + 'input.substr(peg$currPos, ' + + eval(ast.consts[bc[ip + 1]]).length + + ').toLowerCase() === ' + + c(bc[ip + 1]), + 1 + ); + break; + + case op.MATCH_REGEXP: // MATCH_REGEXP r, a, f, ... + compileCondition( + c(bc[ip + 1]) + '.test(input.charAt(peg$currPos))', + 1 + ); + break; + + case op.ACCEPT_N: // ACCEPT_N n + parts.push(stack.push( + bc[ip + 1] > 1 + ? 'input.substr(peg$currPos, ' + bc[ip + 1] + ')' + : 'input.charAt(peg$currPos)' + )); + parts.push( + bc[ip + 1] > 1 + ? 'peg$currPos += ' + bc[ip + 1] + ';' + : 'peg$currPos++;' + ); + ip += 2; + break; + + case op.ACCEPT_STRING: // ACCEPT_STRING s + parts.push(stack.push(c(bc[ip + 1]))); + parts.push( + eval(ast.consts[bc[ip + 1]]).length > 1 + ? 'peg$currPos += ' + eval(ast.consts[bc[ip + 1]]).length + ';' + : 'peg$currPos++;' + ); + ip += 2; + break; + + case op.FAIL: // FAIL e + parts.push(stack.push('peg$FAILED')); + parts.push('if (peg$silentFails === 0) { peg$fail(' + c(bc[ip + 1]) + '); }'); + ip += 2; + break; + + case op.LOAD_SAVED_POS: // LOAD_SAVED_POS p + parts.push('peg$savedPos = ' + stack.index(bc[ip + 1]) + ';'); + ip += 2; + break; + + case op.UPDATE_SAVED_POS: // UPDATE_SAVED_POS + parts.push('peg$savedPos = peg$currPos;'); + ip++; + break; + + case op.CALL: // CALL f, n, pc, p1, p2, ..., pN + compileCall(); + break; + + case op.RULE: // RULE r + parts.push(stack.push("peg$parse" + ast.rules[bc[ip + 1]].name + "()")); + ip += 2; + break; + + case op.SILENT_FAILS_ON: // SILENT_FAILS_ON + parts.push('peg$silentFails++;'); + ip++; + break; + + case op.SILENT_FAILS_OFF: // SILENT_FAILS_OFF + parts.push('peg$silentFails--;'); + ip++; + break; + + default: + throw new Error("Invalid opcode: " + bc[ip] + "."); + } + } + + return parts.join('\n'); + } + + code = compile(rule.bytecode); + + parts.push('function peg$parse' + rule.name + '() {'); + + if (options.trace) { + parts.push([ + ' var ' + arrays.map(arrays.range(0, stack.maxSp + 1), s).join(', ') + ',', + ' startPos = peg$currPos;' + ].join('\n')); + } else { + parts.push( + ' var ' + arrays.map(arrays.range(0, stack.maxSp + 1), s).join(', ') + ';' + ); + } + + parts.push(indent2(generateRuleHeader( + '"' + js.stringEscape(rule.name) + '"', + asts.indexOfRule(ast, rule.name) + ))); + parts.push(indent2(code)); + parts.push(indent2(generateRuleFooter( + '"' + js.stringEscape(rule.name) + '"', + s(0) + ))); + + parts.push('}'); + + return parts.join('\n'); + } + + function generateToplevel() { + var parts = [], + startRuleIndices, startRuleIndex, + startRuleFunctions, startRuleFunction, + ruleNames; + + parts.push([ + 'function peg$subclass(child, parent) {', + ' function ctor() { this.constructor = child; }', + ' ctor.prototype = parent.prototype;', + ' child.prototype = new ctor();', + '}', + '', + 'function peg$SyntaxError(message, expected, found, location) {', + ' this.message = message;', + ' this.expected = expected;', + ' this.found = found;', + ' this.location = location;', + ' this.name = "SyntaxError";', + '', + ' if (typeof Error.captureStackTrace === "function") {', + ' Error.captureStackTrace(this, peg$SyntaxError);', + ' }', + '}', + '', + 'peg$subclass(peg$SyntaxError, Error);', + '', + 'peg$SyntaxError.buildMessage = function(expected, found) {', + ' var DESCRIBE_EXPECTATION_FNS = {', + ' literal: function(expectation) {', + ' return "\\\"" + literalEscape(expectation.text) + "\\\"";', + ' },', + '', + ' "class": function(expectation) {', + ' var escapedParts = "",', + ' i;', + '', + ' for (i = 0; i < expectation.parts.length; i++) {', + ' escapedParts += expectation.parts[i] instanceof Array', + ' ? classEscape(expectation.parts[i][0]) + "-" + classEscape(expectation.parts[i][1])', + ' : classEscape(expectation.parts[i]);', + ' }', + '', + ' return "[" + (expectation.inverted ? "^" : "") + escapedParts + "]";', + ' },', + '', + ' any: function(expectation) {', + ' return "any character";', + ' },', + '', + ' end: function(expectation) {', + ' return "end of input";', + ' },', + '', + ' other: function(expectation) {', + ' return expectation.description;', + ' }', + ' };', + '', + ' function hex(ch) {', + ' return ch.charCodeAt(0).toString(16).toUpperCase();', + ' }', + '', + ' function literalEscape(s) {', + ' return s', + ' .replace(/\\\\/g, \'\\\\\\\\\')', // backslash + ' .replace(/"/g, \'\\\\"\')', // closing double quote + ' .replace(/\\0/g, \'\\\\0\')', // null + ' .replace(/\\t/g, \'\\\\t\')', // horizontal tab + ' .replace(/\\n/g, \'\\\\n\')', // line feed + ' .replace(/\\r/g, \'\\\\r\')', // carriage return + ' .replace(/[\\x00-\\x0F]/g, function(ch) { return \'\\\\x0\' + hex(ch); })', + ' .replace(/[\\x10-\\x1F\\x7F-\\x9F]/g, function(ch) { return \'\\\\x\' + hex(ch); });', + ' }', + '', + ' function classEscape(s) {', + ' return s', + ' .replace(/\\\\/g, \'\\\\\\\\\')', // backslash + ' .replace(/\\]/g, \'\\\\]\')', // closing bracket + ' .replace(/\\^/g, \'\\\\^\')', // caret + ' .replace(/-/g, \'\\\\-\')', // dash + ' .replace(/\\0/g, \'\\\\0\')', // null + ' .replace(/\\t/g, \'\\\\t\')', // horizontal tab + ' .replace(/\\n/g, \'\\\\n\')', // line feed + ' .replace(/\\r/g, \'\\\\r\')', // carriage return + ' .replace(/[\\x00-\\x0F]/g, function(ch) { return \'\\\\x0\' + hex(ch); })', + ' .replace(/[\\x10-\\x1F\\x7F-\\x9F]/g, function(ch) { return \'\\\\x\' + hex(ch); });', + ' }', + '', + ' function describeExpectation(expectation) {', + ' return DESCRIBE_EXPECTATION_FNS[expectation.type](expectation);', + ' }', + '', + ' function describeExpected(expected) {', + ' var descriptions = new Array(expected.length),', + ' i, j;', + '', + ' for (i = 0; i < expected.length; i++) {', + ' descriptions[i] = describeExpectation(expected[i]);', + ' }', + '', + ' descriptions.sort();', + '', + ' if (descriptions.length > 0) {', + ' for (i = 1, j = 1; i < descriptions.length; i++) {', + ' if (descriptions[i - 1] !== descriptions[i]) {', + ' descriptions[j] = descriptions[i];', + ' j++;', + ' }', + ' }', + ' descriptions.length = j;', + ' }', + '', + ' switch (descriptions.length) {', + ' case 1:', + ' return descriptions[0];', + '', + ' case 2:', + ' return descriptions[0] + " or " + descriptions[1];', + '', + ' default:', + ' return descriptions.slice(0, -1).join(", ")', + ' + ", or "', + ' + descriptions[descriptions.length - 1];', + ' }', + ' }', + '', + ' function describeFound(found) {', + ' return found ? "\\"" + literalEscape(found) + "\\"" : "end of input";', + ' }', + '', + ' return "Expected " + describeExpected(expected) + " but " + describeFound(found) + " found.";', + '};', + '' + ].join('\n')); + + if (options.trace) { + parts.push([ + 'function peg$DefaultTracer() {', + ' this.indentLevel = 0;', + '}', + '', + 'peg$DefaultTracer.prototype.trace = function(event) {', + ' var that = this;', + '', + ' function log(event) {', + ' function repeat(string, n) {', + ' var result = "", i;', + '', + ' for (i = 0; i < n; i++) {', + ' result += string;', + ' }', + '', + ' return result;', + ' }', + '', + ' function pad(string, length) {', + ' return string + repeat(" ", length - string.length);', + ' }', + '', + ' if (typeof console === "object") {', // IE 8-10 + ' console.log(', + ' event.location.start.line + ":" + event.location.start.column + "-"', + ' + event.location.end.line + ":" + event.location.end.column + " "', + ' + pad(event.type, 10) + " "', + ' + repeat(" ", that.indentLevel) + event.rule', + ' );', + ' }', + ' }', + '', + ' switch (event.type) {', + ' case "rule.enter":', + ' log(event);', + ' this.indentLevel++;', + ' break;', + '', + ' case "rule.match":', + ' this.indentLevel--;', + ' log(event);', + ' break;', + '', + ' case "rule.fail":', + ' this.indentLevel--;', + ' log(event);', + ' break;', + '', + ' default:', + ' throw new Error("Invalid event type: " + event.type + ".");', + ' }', + '};', + '' + ].join('\n')); + } + + parts.push([ + 'function peg$parse(input, options) {', + ' options = options !== void 0 ? options : {};', + '', + ' var peg$FAILED = {},', + '' + ].join('\n')); + + if (options.optimize === "size") { + startRuleIndices = '{ ' + + arrays.map( + options.allowedStartRules, + function(r) { return r + ': ' + asts.indexOfRule(ast, r); } + ).join(', ') + + ' }'; + startRuleIndex = asts.indexOfRule(ast, options.allowedStartRules[0]); + + parts.push([ + ' peg$startRuleIndices = ' + startRuleIndices + ',', + ' peg$startRuleIndex = ' + startRuleIndex + ',' + ].join('\n')); + } else { + startRuleFunctions = '{ ' + + arrays.map( + options.allowedStartRules, + function(r) { return r + ': peg$parse' + r; } + ).join(', ') + + ' }'; + startRuleFunction = 'peg$parse' + options.allowedStartRules[0]; + + parts.push([ + ' peg$startRuleFunctions = ' + startRuleFunctions + ',', + ' peg$startRuleFunction = ' + startRuleFunction + ',' + ].join('\n')); + } + + parts.push(''); + + parts.push(indent6(generateTables())); + + parts.push([ + '', + ' peg$currPos = 0,', + ' peg$savedPos = 0,', + ' peg$posDetailsCache = [{ line: 1, column: 1 }],', + ' peg$maxFailPos = 0,', + ' peg$maxFailExpected = [],', + ' peg$silentFails = 0,', // 0 = report failures, > 0 = silence failures + '' + ].join('\n')); + + if (options.cache) { + parts.push([ + ' peg$resultsCache = {},', + '' + ].join('\n')); + } + + if (options.trace) { + if (options.optimize === "size") { + ruleNames = '[' + + arrays.map( + ast.rules, + function(r) { return '"' + js.stringEscape(r.name) + '"'; } + ).join(', ') + + ']'; + + parts.push([ + ' peg$ruleNames = ' + ruleNames + ',', + '' + ].join('\n')); + } + + parts.push([ + ' peg$tracer = "tracer" in options ? options.tracer : new peg$DefaultTracer(),', + '' + ].join('\n')); + } + + parts.push([ + ' peg$result;', + '' + ].join('\n')); + + if (options.optimize === "size") { + parts.push([ + ' if ("startRule" in options) {', + ' if (!(options.startRule in peg$startRuleIndices)) {', + ' throw new Error("Can\'t start parsing from rule \\"" + options.startRule + "\\".");', + ' }', + '', + ' peg$startRuleIndex = peg$startRuleIndices[options.startRule];', + ' }' + ].join('\n')); + } else { + parts.push([ + ' if ("startRule" in options) {', + ' if (!(options.startRule in peg$startRuleFunctions)) {', + ' throw new Error("Can\'t start parsing from rule \\"" + options.startRule + "\\".");', + ' }', + '', + ' peg$startRuleFunction = peg$startRuleFunctions[options.startRule];', + ' }' + ].join('\n')); + } + + parts.push([ + '', + ' function text() {', + ' return input.substring(peg$savedPos, peg$currPos);', + ' }', + '', + ' function location() {', + ' return peg$computeLocation(peg$savedPos, peg$currPos);', + ' }', + '', + ' function expected(description, location) {', + ' location = location !== void 0 ? location : peg$computeLocation(peg$savedPos, peg$currPos)', + '', + ' throw peg$buildStructuredError(', + ' [peg$otherExpectation(description)],', + ' input.substring(peg$savedPos, peg$currPos),', + ' location', + ' );', + ' }', + '', + ' function error(message, location) {', + ' location = location !== void 0 ? location : peg$computeLocation(peg$savedPos, peg$currPos)', + '', + ' throw peg$buildSimpleError(message, location);', + ' }', + '', + ' function peg$literalExpectation(text, ignoreCase) {', + ' return { type: "literal", text: text, ignoreCase: ignoreCase };', + ' }', + '', + ' function peg$classExpectation(parts, inverted, ignoreCase) {', + ' return { type: "class", parts: parts, inverted: inverted, ignoreCase: ignoreCase };', + ' }', + '', + ' function peg$anyExpectation() {', + ' return { type: "any" };', + ' }', + '', + ' function peg$endExpectation() {', + ' return { type: "end" };', + ' }', + '', + ' function peg$otherExpectation(description) {', + ' return { type: "other", description: description };', + ' }', + '', + ' function peg$computePosDetails(pos) {', + ' var details = peg$posDetailsCache[pos], p;', + '', + ' if (details) {', + ' return details;', + ' } else {', + ' p = pos - 1;', + ' while (!peg$posDetailsCache[p]) {', + ' p--;', + ' }', + '', + ' details = peg$posDetailsCache[p];', + ' details = {', + ' line: details.line,', + ' column: details.column', + ' };', + '', + ' while (p < pos) {', + ' if (input.charCodeAt(p) === 10) {', + ' details.line++;', + ' details.column = 1;', + ' } else {', + ' details.column++;', + ' }', + '', + ' p++;', + ' }', + '', + ' peg$posDetailsCache[pos] = details;', + ' return details;', + ' }', + ' }', + '', + ' function peg$computeLocation(startPos, endPos) {', + ' var startPosDetails = peg$computePosDetails(startPos),', + ' endPosDetails = peg$computePosDetails(endPos);', + '', + ' return {', + ' start: {', + ' offset: startPos,', + ' line: startPosDetails.line,', + ' column: startPosDetails.column', + ' },', + ' end: {', + ' offset: endPos,', + ' line: endPosDetails.line,', + ' column: endPosDetails.column', + ' }', + ' };', + ' }', + '', + ' function peg$fail(expected) {', + ' if (peg$currPos < peg$maxFailPos) { return; }', + '', + ' if (peg$currPos > peg$maxFailPos) {', + ' peg$maxFailPos = peg$currPos;', + ' peg$maxFailExpected = [];', + ' }', + '', + ' peg$maxFailExpected.push(expected);', + ' }', + '', + ' function peg$buildSimpleError(message, location) {', + ' return new peg$SyntaxError(message, null, null, location);', + ' }', + '', + ' function peg$buildStructuredError(expected, found, location) {', + ' return new peg$SyntaxError(', + ' peg$SyntaxError.buildMessage(expected, found),', + ' expected,', + ' found,', + ' location', + ' );', + ' }', + '' + ].join('\n')); + + if (options.optimize === "size") { + parts.push(indent2(generateInterpreter())); + parts.push(''); + } else { + arrays.each(ast.rules, function(rule) { + parts.push(indent2(generateRuleFunction(rule))); + parts.push(''); + }); + } + + if (ast.initializer) { + parts.push(indent2(ast.initializer.code)); + parts.push(''); + } + + if (options.optimize === "size") { + parts.push(' peg$result = peg$parseRule(peg$startRuleIndex);'); + } else { + parts.push(' peg$result = peg$startRuleFunction();'); + } + + parts.push([ + '', + ' if (peg$result !== peg$FAILED && peg$currPos === input.length) {', + ' return peg$result;', + ' } else {', + ' if (peg$result !== peg$FAILED && peg$currPos < input.length) {', + ' peg$fail(peg$endExpectation());', + ' }', + '', + ' throw peg$buildStructuredError(', + ' peg$maxFailExpected,', + ' peg$maxFailPos < input.length ? input.charAt(peg$maxFailPos) : null,', + ' peg$maxFailPos < input.length', + ' ? peg$computeLocation(peg$maxFailPos, peg$maxFailPos + 1)', + ' : peg$computeLocation(peg$maxFailPos, peg$maxFailPos)', + ' );', + ' }', + '}' + ].join('\n')); + + return parts.join('\n'); + } + + function generateWrapper(toplevelCode) { + function generateGeneratedByComment() { + return [ + '/*', + ' * Generated by PEG.js 0.10.0.', + ' *', + ' * http://pegjs.org/', + ' */' + ].join('\n'); + } + + function generateParserObject() { + return options.trace + ? [ + '{', + ' SyntaxError: peg$SyntaxError,', + ' DefaultTracer: peg$DefaultTracer,', + ' parse: peg$parse', + '}' + ].join('\n') + : [ + '{', + ' SyntaxError: peg$SyntaxError,', + ' parse: peg$parse', + '}' + ].join('\n'); + } + + var generators = { + bare: function() { + return [ + generateGeneratedByComment(), + '(function() {', + ' "use strict";', + '', + indent2(toplevelCode), + '', + indent2('return ' + generateParserObject() + ';'), + '})()' + ].join('\n'); + }, + + commonjs: function() { + var parts = [], + dependencyVars = objects.keys(options.dependencies), + requires = arrays.map( + dependencyVars, + function(variable) { + return variable + + ' = require("' + + js.stringEscape(options.dependencies[variable]) + + '")'; + } + ); + + parts.push([ + generateGeneratedByComment(), + '', + '"use strict";', + '' + ].join('\n')); + + if (requires.length > 0) { + parts.push('var ' + requires.join(', ') + ';'); + parts.push(''); + } + + parts.push([ + toplevelCode, + '', + 'module.exports = ' + generateParserObject() + ';', + '' + ].join('\n')); + + return parts.join('\n'); + }, + + amd: function() { + var dependencyIds = objects.values(options.dependencies), + dependencyVars = objects.keys(options.dependencies), + dependencies = '[' + + arrays.map( + dependencyIds, + function(id) { return '"' + js.stringEscape(id) + '"'; } + ).join(', ') + + ']', + params = dependencyVars.join(', '); + + return [ + generateGeneratedByComment(), + 'define(' + dependencies + ', function(' + params + ') {', + ' "use strict";', + '', + indent2(toplevelCode), + '', + indent2('return ' + generateParserObject() + ';'), + '});', + '' + ].join('\n'); + }, + + globals: function() { + return [ + generateGeneratedByComment(), + '(function(root) {', + ' "use strict";', + '', + indent2(toplevelCode), + '', + indent2('root.' + options.exportVar + ' = ' + generateParserObject() + ';'), + '})(this);', + '' + ].join('\n'); + }, + + umd: function() { + var parts = [], + dependencyIds = objects.values(options.dependencies), + dependencyVars = objects.keys(options.dependencies), + dependencies = '[' + + arrays.map( + dependencyIds, + function(id) { return '"' + js.stringEscape(id) + '"'; } + ).join(', ') + + ']', + requires = arrays.map( + dependencyIds, + function(id) { return 'require("' + js.stringEscape(id) + '")'; } + ).join(', '), + params = dependencyVars.join(', '); + + parts.push([ + generateGeneratedByComment(), + '(function(root, factory) {', + ' if (typeof define === "function" && define.amd) {', + ' define(' + dependencies + ', factory);', + ' } else if (typeof module === "object" && module.exports) {', + ' module.exports = factory(' + requires + ');' + ].join('\n')); + + if (options.exportVar !== null) { + parts.push([ + ' } else {', + ' root.' + options.exportVar + ' = factory();' + ].join('\n')); + } + + parts.push([ + ' }', + '})(this, function(' + params + ') {', + ' "use strict";', + '', + indent2(toplevelCode), + '', + indent2('return ' + generateParserObject() + ';'), + '});', + '' + ].join('\n')); + + return parts.join('\n'); + } + }; + + return generators[options.format](); + } + + ast.code = generateWrapper(generateToplevel()); +} + +module.exports = generateJS; diff --git a/cordova/node_modules/pegjs/lib/compiler/passes/remove-proxy-rules.js b/cordova/node_modules/pegjs/lib/compiler/passes/remove-proxy-rules.js new file mode 100644 index 0000000..8d50548 --- /dev/null +++ b/cordova/node_modules/pegjs/lib/compiler/passes/remove-proxy-rules.js @@ -0,0 +1,42 @@ +"use strict"; + +var arrays = require("../../utils/arrays"), + visitor = require("../visitor"); + +/* + * Removes proxy rules -- that is, rules that only delegate to other rule. + */ +function removeProxyRules(ast, options) { + function isProxyRule(node) { + return node.type === "rule" && node.expression.type === "rule_ref"; + } + + function replaceRuleRefs(ast, from, to) { + var replace = visitor.build({ + rule_ref: function(node) { + if (node.name === from) { + node.name = to; + } + } + }); + + replace(ast); + } + + var indices = []; + + arrays.each(ast.rules, function(rule, i) { + if (isProxyRule(rule)) { + replaceRuleRefs(ast, rule.name, rule.expression.name); + if (!arrays.contains(options.allowedStartRules, rule.name)) { + indices.push(i); + } + } + }); + + indices.reverse(); + + arrays.each(indices, function(i) { ast.rules.splice(i, 1); }); +} + +module.exports = removeProxyRules; diff --git a/cordova/node_modules/pegjs/lib/compiler/passes/report-duplicate-labels.js b/cordova/node_modules/pegjs/lib/compiler/passes/report-duplicate-labels.js new file mode 100644 index 0000000..16a0c11 --- /dev/null +++ b/cordova/node_modules/pegjs/lib/compiler/passes/report-duplicate-labels.js @@ -0,0 +1,54 @@ +"use strict"; + +var GrammarError = require("../../grammar-error"), + arrays = require("../../utils/arrays"), + objects = require("../../utils/objects"), + visitor = require("../visitor"); + +/* Checks that each label is defined only once within each scope. */ +function reportDuplicateLabels(ast) { + function checkExpressionWithClonedEnv(node, env) { + check(node.expression, objects.clone(env)); + } + + var check = visitor.build({ + rule: function(node) { + check(node.expression, { }); + }, + + choice: function(node, env) { + arrays.each(node.alternatives, function(alternative) { + check(alternative, objects.clone(env)); + }); + }, + + action: checkExpressionWithClonedEnv, + + labeled: function(node, env) { + if (env.hasOwnProperty(node.label)) { + throw new GrammarError( + "Label \"" + node.label + "\" is already defined " + + "at line " + env[node.label].start.line + ", " + + "column " + env[node.label].start.column + ".", + node.location + ); + } + + check(node.expression, env); + + env[node.label] = node.location; + }, + + text: checkExpressionWithClonedEnv, + simple_and: checkExpressionWithClonedEnv, + simple_not: checkExpressionWithClonedEnv, + optional: checkExpressionWithClonedEnv, + zero_or_more: checkExpressionWithClonedEnv, + one_or_more: checkExpressionWithClonedEnv, + group: checkExpressionWithClonedEnv + }); + + check(ast); +} + +module.exports = reportDuplicateLabels; diff --git a/cordova/node_modules/pegjs/lib/compiler/passes/report-duplicate-rules.js b/cordova/node_modules/pegjs/lib/compiler/passes/report-duplicate-rules.js new file mode 100644 index 0000000..c621d37 --- /dev/null +++ b/cordova/node_modules/pegjs/lib/compiler/passes/report-duplicate-rules.js @@ -0,0 +1,28 @@ +"use strict"; + +var GrammarError = require("../../grammar-error"), + visitor = require("../visitor"); + +/* Checks that each rule is defined only once. */ +function reportDuplicateRules(ast) { + var rules = {}; + + var check = visitor.build({ + rule: function(node) { + if (rules.hasOwnProperty(node.name)) { + throw new GrammarError( + "Rule \"" + node.name + "\" is already defined " + + "at line " + rules[node.name].start.line + ", " + + "column " + rules[node.name].start.column + ".", + node.location + ); + } + + rules[node.name] = node.location; + } + }); + + check(ast); +} + +module.exports = reportDuplicateRules; diff --git a/cordova/node_modules/pegjs/lib/compiler/passes/report-infinite-recursion.js b/cordova/node_modules/pegjs/lib/compiler/passes/report-infinite-recursion.js new file mode 100644 index 0000000..1230a2f --- /dev/null +++ b/cordova/node_modules/pegjs/lib/compiler/passes/report-infinite-recursion.js @@ -0,0 +1,57 @@ +"use strict"; + +var arrays = require("../../utils/arrays"), + GrammarError = require("../../grammar-error"), + asts = require("../asts"), + visitor = require("../visitor"); + +/* + * Reports left recursion in the grammar, which prevents infinite recursion in + * the generated parser. + * + * Both direct and indirect recursion is detected. The pass also correctly + * reports cases like this: + * + * start = "a"? start + * + * In general, if a rule reference can be reached without consuming any input, + * it can lead to left recursion. + */ +function reportInfiniteRecursion(ast) { + var visitedRules = []; + + var check = visitor.build({ + rule: function(node) { + visitedRules.push(node.name); + check(node.expression); + visitedRules.pop(node.name); + }, + + sequence: function(node) { + arrays.every(node.elements, function(element) { + check(element); + + return !asts.alwaysConsumesOnSuccess(ast, element); + }); + }, + + rule_ref: function(node) { + if (arrays.contains(visitedRules, node.name)) { + visitedRules.push(node.name); + + throw new GrammarError( + "Possible infinite loop when parsing (left recursion: " + + visitedRules.join(" -> ") + + ").", + node.location + ); + } + + check(asts.findRule(ast, node.name)); + } + }); + + check(ast); +} + +module.exports = reportInfiniteRecursion; diff --git a/cordova/node_modules/pegjs/lib/compiler/passes/report-infinite-repetition.js b/cordova/node_modules/pegjs/lib/compiler/passes/report-infinite-repetition.js new file mode 100644 index 0000000..e6f12c0 --- /dev/null +++ b/cordova/node_modules/pegjs/lib/compiler/passes/report-infinite-repetition.js @@ -0,0 +1,35 @@ +"use strict"; + +var GrammarError = require("../../grammar-error"), + asts = require("../asts"), + visitor = require("../visitor"); + +/* + * Reports expressions that don't consume any input inside |*| or |+| in the + * grammar, which prevents infinite loops in the generated parser. + */ +function reportInfiniteRepetition(ast) { + var check = visitor.build({ + zero_or_more: function(node) { + if (!asts.alwaysConsumesOnSuccess(ast, node.expression)) { + throw new GrammarError( + "Possible infinite loop when parsing (repetition used with an expression that may not consume any input).", + node.location + ); + } + }, + + one_or_more: function(node) { + if (!asts.alwaysConsumesOnSuccess(ast, node.expression)) { + throw new GrammarError( + "Possible infinite loop when parsing (repetition used with an expression that may not consume any input).", + node.location + ); + } + } + }); + + check(ast); +} + +module.exports = reportInfiniteRepetition; diff --git a/cordova/node_modules/pegjs/lib/compiler/passes/report-undefined-rules.js b/cordova/node_modules/pegjs/lib/compiler/passes/report-undefined-rules.js new file mode 100644 index 0000000..c71b03f --- /dev/null +++ b/cordova/node_modules/pegjs/lib/compiler/passes/report-undefined-rules.js @@ -0,0 +1,23 @@ +"use strict"; + +var GrammarError = require("../../grammar-error"), + asts = require("../asts"), + visitor = require("../visitor"); + +/* Checks that all referenced rules exist. */ +function reportUndefinedRules(ast) { + var check = visitor.build({ + rule_ref: function(node) { + if (!asts.findRule(ast, node.name)) { + throw new GrammarError( + "Rule \"" + node.name + "\" is not defined.", + node.location + ); + } + } + }); + + check(ast); +} + +module.exports = reportUndefinedRules; diff --git a/cordova/node_modules/pegjs/lib/compiler/visitor.js b/cordova/node_modules/pegjs/lib/compiler/visitor.js new file mode 100644 index 0000000..0a447bc --- /dev/null +++ b/cordova/node_modules/pegjs/lib/compiler/visitor.js @@ -0,0 +1,72 @@ +"use strict"; + +var objects = require("../utils/objects"), + arrays = require("../utils/arrays"); + +/* Simple AST node visitor builder. */ +var visitor = { + build: function(functions) { + function visit(node) { + return functions[node.type].apply(null, arguments); + } + + function visitNop() { } + + function visitExpression(node) { + var extraArgs = Array.prototype.slice.call(arguments, 1); + + visit.apply(null, [node.expression].concat(extraArgs)); + } + + function visitChildren(property) { + return function(node) { + var extraArgs = Array.prototype.slice.call(arguments, 1); + + arrays.each(node[property], function(child) { + visit.apply(null, [child].concat(extraArgs)); + }); + }; + } + + var DEFAULT_FUNCTIONS = { + grammar: function(node) { + var extraArgs = Array.prototype.slice.call(arguments, 1); + + if (node.initializer) { + visit.apply(null, [node.initializer].concat(extraArgs)); + } + + arrays.each(node.rules, function(rule) { + visit.apply(null, [rule].concat(extraArgs)); + }); + }, + + initializer: visitNop, + rule: visitExpression, + named: visitExpression, + choice: visitChildren("alternatives"), + action: visitExpression, + sequence: visitChildren("elements"), + labeled: visitExpression, + text: visitExpression, + simple_and: visitExpression, + simple_not: visitExpression, + optional: visitExpression, + zero_or_more: visitExpression, + one_or_more: visitExpression, + group: visitExpression, + semantic_and: visitNop, + semantic_not: visitNop, + rule_ref: visitNop, + literal: visitNop, + "class": visitNop, + any: visitNop + }; + + objects.defaults(functions, DEFAULT_FUNCTIONS); + + return visit; + } +}; + +module.exports = visitor; |
