diff --git a/Makefile b/Makefile
index 5df7cd9..d99a681 100644
--- a/Makefile
+++ b/Makefile
@@ -8,8 +8,9 @@ PEGJS_VERSION = `cat $(VERSION_FILE)`
MODULES = utils \
grammar-error \
parser \
- compiler/passes/allocate-registers \
- compiler/passes/generate-code \
+ compiler/opcodes \
+ compiler/passes/generate-bytecode \
+ compiler/passes/generate-javascript \
compiler/passes/remove-proxy-rules \
compiler/passes/report-left-recursion \
compiler/passes/report-missing-rules \
diff --git a/README.md b/README.md
index 59d7ed9..4151146 100644
--- a/README.md
+++ b/README.md
@@ -108,6 +108,8 @@ object to `PEG.buildParser`. The following options are supported:
* `output` — if set to `"parser"`, the method will return generated parser
object; if set to `"source"`, it will return parser source code as a string
(default: `"parser"`)
+ * `optimize`— selects between optimizing the generated parser for parsing
+ speed (`"speed"`) or code size (`"size"`) (default: `"speed"`)
Using the Parser
----------------
diff --git a/benchmark/index.css b/benchmark/index.css
index 9156969..adb079b 100644
--- a/benchmark/index.css
+++ b/benchmark/index.css
@@ -24,11 +24,11 @@ table tr.total td.parse-speed .value { font-size: 175%; }
a, a:visited { color: #3d586c; }
#options {
- width: 46em;
- margin: 2em auto; border-radius: .5em; -moz-border-radius: .5em; padding: .5em 1em;
- text-align: center;
+ width: 45em;
+ margin: 2em auto; border-radius: .5em; -moz-border-radius: .5em; padding: .5em 1.5em;
background-color: #f0f0f0;
}
#options #run-count { width: 3em; }
#options #cache { margin-left: 2em; }
-#options #run { width: 5em; margin-left: 2em; }
+#options label[for=optimize] { margin-left: 2em; }
+#options #run { float:right; width: 5em; }
diff --git a/benchmark/index.html b/benchmark/index.html
index 5c81418..92cf58a 100644
--- a/benchmark/index.html
+++ b/benchmark/index.html
@@ -13,6 +13,11 @@
times
+
+
diff --git a/benchmark/index.js b/benchmark/index.js
index 874f196..f13aa41 100644
--- a/benchmark/index.js
+++ b/benchmark/index.js
@@ -63,7 +63,8 @@ $("#run").click(function() {
}
var options = {
- cache: $("#cache").is(":checked"),
+ cache: $("#cache").is(":checked"),
+ optimize: $("#optimize").val()
};
Runner.run(benchmarks, runCount, options, {
diff --git a/benchmark/run b/benchmark/run
index 1882fb1..1e9081b 100755
--- a/benchmark/run
+++ b/benchmark/run
@@ -81,6 +81,8 @@ function printHelp() {
util.puts("Options:");
util.puts(" -n, --run-count number of runs (default: 10)");
util.puts(" --cache make tested parsers cache results");
+ util.puts(" -o, --optimize select optimization for speed or size (default:");
+ util.puts(" speed)");
}
function exitSuccess() {
@@ -111,7 +113,10 @@ function nextArg() {
/* Main */
var runCount = 10;
-var options = { };
+var options = {
+ cache: false,
+ optimize: "speed"
+};
while (args.length > 0 && isOption(args[0])) {
switch (args[0]) {
@@ -131,6 +136,18 @@ while (args.length > 0 && isOption(args[0])) {
options.cache = true;
break;
+ case "-o":
+ case "--optimize":
+ nextArg();
+ if (args.length === 0) {
+ abort("Missing parameter of the -o/--optimize option.");
+ }
+ if (args[0] !== "speed" && args[0] !== "size") {
+ abort("Optimization goal must be either \"speed\" or \"size\".");
+ }
+ options.optimize = args[0];
+ break;
+
case "-h":
case "--help":
printHelp();
diff --git a/bin/pegjs b/bin/pegjs
index 3c1421e..fd3c586 100755
--- a/bin/pegjs
+++ b/bin/pegjs
@@ -29,6 +29,8 @@ function printHelp() {
util.puts(" parser will be allowed to start parsing");
util.puts(" from (default: the first rule in the");
util.puts(" grammar)");
+ util.puts(" -o, --optimize select optimization for speed or size (default:");
+ util.puts(" speed)");
util.puts(" -v, --version print version information and exit");
util.puts(" -h, --help print help and exit");
}
@@ -71,8 +73,9 @@ function readStream(inputStream, callback) {
/* This makes the generated parser a CommonJS module by default. */
var exportVar = "module.exports";
var options = {
- cache: false,
- output: "source"
+ cache: false,
+ output: "source",
+ optimize: "speed"
};
while (args.length > 0 && isOption(args[0])) {
@@ -100,6 +103,18 @@ while (args.length > 0 && isOption(args[0])) {
.map(function(s) { return s.trim() });
break;
+ case "-o":
+ case "--optimize":
+ nextArg();
+ if (args.length === 0) {
+ abort("Missing parameter of the -o/--optimize option.");
+ }
+ if (args[0] !== "speed" && args[0] !== "size") {
+ abort("Optimization goal must be either \"speed\" or \"size\".");
+ }
+ options.optimize = args[0];
+ break;
+
case "-v":
case "--version":
printVersion();
diff --git a/lib/compiler.js b/lib/compiler.js
index 0ebd2cd..3d107c0 100644
--- a/lib/compiler.js
+++ b/lib/compiler.js
@@ -11,8 +11,8 @@ module.exports = {
"reportMissingRules",
"reportLeftRecursion",
"removeProxyRules",
- "allocateRegisters",
- "generateCode"
+ "generateBytecode",
+ "generateJavascript"
],
/*
diff --git a/lib/compiler/opcodes.js b/lib/compiler/opcodes.js
new file mode 100644
index 0000000..fb3fa71
--- /dev/null
+++ b/lib/compiler/opcodes.js
@@ -0,0 +1,46 @@
+/* Bytecode instruction opcodes. */
+module.exports = {
+ /* Stack Manipulation */
+ PUSH: 0, // PUSH c
+ PUSH_CURR_POS: 1, // PUSH_CURR_POS
+ POP: 2, // POP
+ POP_CURR_POS: 3, // POP_CURR_POS
+ POP_N: 4, // POP_N n
+ NIP: 5, // NIP
+ NIP_CURR_POS: 6, // NIP_CURR_POS
+ APPEND: 7, // APPEND
+ WRAP: 8, // WRAP n
+ TEXT: 9, // TEXT
+
+ /* Conditions and Loops */
+
+ IF: 10, // IF t, f
+ IF_ERROR: 11, // IF_ERROR t, f
+ IF_NOT_ERROR: 12, // IF_NOT_ERROR t, f
+ WHILE_NOT_ERROR: 13, // WHILE_NOT_ERROR b
+
+ /* Matching */
+
+ MATCH_ANY: 14, // MATCH_ANY a, f, ...
+ MATCH_STRING: 15, // MATCH_STRING s, a, f, ...
+ MATCH_STRING_IC: 16, // MATCH_STRING_IC s, a, f, ...
+ MATCH_REGEXP: 17, // MATCH_REGEXP r, a, f, ...
+ ACCEPT_N: 18, // ACCEPT_N n
+ ACCEPT_STRING: 19, // ACCEPT_STRING s
+ FAIL: 20, // FAIL e
+
+ /* Calls */
+
+ REPORT_SAVED_POS: 21, // REPORT_SAVED_POS p
+ REPORT_CURR_POS: 22, // REPORT_CURR_POS
+ CALL: 23, // CALL f, n, pc, p1, p2, ..., pN
+
+ /* Rules */
+
+ RULE: 24, // RULE r
+
+ /* Failure Reporting */
+
+ SILENT_FAILS_ON: 25, // SILENT_FAILS_ON
+ SILENT_FAILS_OFF: 26 // SILENT_FAILS_FF
+};
diff --git a/lib/compiler/passes.js b/lib/compiler/passes.js
index a4c3723..bf3a0bf 100644
--- a/lib/compiler/passes.js
+++ b/lib/compiler/passes.js
@@ -9,6 +9,6 @@ module.exports = {
reportMissingRules: require("./passes/report-missing-rules"),
reportLeftRecursion: require("./passes/report-left-recursion"),
removeProxyRules: require("./passes/remove-proxy-rules"),
- allocateRegisters: require("./passes/allocate-registers"),
- generateCode: require("./passes/generate-code")
+ generateBytecode: require("./passes/generate-bytecode"),
+ generateJavascript: require("./passes/generate-javascript")
};
diff --git a/lib/compiler/passes/allocate-registers.js b/lib/compiler/passes/allocate-registers.js
deleted file mode 100644
index 7ec8af7..0000000
--- a/lib/compiler/passes/allocate-registers.js
+++ /dev/null
@@ -1,230 +0,0 @@
-var utils = require("../../utils");
-
-/*
- * Allocates registers that the generated code for each node will use to store
- * match results and parse positions. For "action", "semantic_and" and
- * "semantic_or" nodes it also computes visibility of labels at the point of
- * action/predicate code execution and a mapping from label names to registers
- * that will contain the labeled values.
- *
- * The following will hold after running this pass:
- *
- * * All nodes except "grammar" and "rule" nodes will have a |resultIndex|
- * property. It will contain an index of a register that will store a match
- * result of the expression represented by the node in generated code.
- *
- * * Some nodes will have a |posIndex| property. It will contain an index of a
- * register that will store a saved parse position in generated code.
- *
- * * All "rule" nodes will contain a |registerCount| property. It will contain
- * the number of registers that will be used by code generated for the
- * rule's expression.
- *
- * * All "action", "semantic_and" and "semantic_or" nodes will have a |params|
- * property. It will contain a mapping from names of labels visible at the
- * point of action/predicate code execution to registers that will contain
- * the labeled values.
- */
-module.exports = function(ast) {
- /*
- * Register allocator that allocates registers from an unlimited
- * integer-indexed pool. It allows allocating and releaseing registers in any
- * order. It also supports reference counting (this simplifies tracking active
- * registers when they store values passed to action/predicate code).
- * Allocating a register allways uses the first free register (the one with
- * the lowest index).
- */
- var registers = (function() {
- var refCounts = []; // reference count for each register that was
- // allocated at least once
-
- return {
- alloc: function() {
- var i;
-
- for (i = 0; i < refCounts.length; i++) {
- if (refCounts[i] === 0) {
- refCounts[i] = 1;
- return i;
- }
- }
-
- refCounts.push(1);
- return refCounts.length - 1;
- },
-
- use: function(index) {
- refCounts[index]++;
- },
-
- release: function(index) {
- refCounts[index]--;
- },
-
- maxIndex: function() {
- return refCounts.length - 1;
- },
-
- reset: function() {
- refCounts = [];
- }
- };
- })();
-
- /*
- * Manages mapping of label names to indices of registers that will store the
- * labeled values as long as they are in scope.
- */
- var vars = (function(registers) {
- var envs = []; // stack of nested environments
-
- return {
- beginScope: function() {
- envs.push({});
- },
-
- endScope: function() {
- var env = envs.pop(), name;
-
- for (name in env) {
- registers.release(env[name]);
- }
- },
-
- add: function(name, index) {
- envs[envs.length - 1][name] = index;
- registers.use(index);
- },
-
- buildParams: function() {
- var env = envs[envs.length - 1], params = {}, name;
-
- for (name in env) {
- params[name] = env[name];
- }
-
- return params;
- }
- };
- })(registers);
-
- function savePos(node, f) {
- node.posIndex = registers.alloc();
- f();
- registers.release(node.posIndex);
- }
-
- function reuseResult(node, subnode) {
- subnode.resultIndex = node.resultIndex;
- }
-
- function allocResult(node, f) {
- node.resultIndex = registers.alloc();
- f();
- registers.release(node.resultIndex);
- }
-
- function scoped(f) {
- vars.beginScope();
- f();
- vars.endScope();
- }
-
- function nop() {}
-
- function computeExpressionScoped(node) {
- scoped(function() { compute(node.expression); });
- }
-
- function computeExpressionScopedReuseResult(node) {
- reuseResult(node, node.expression);
- computeExpressionScoped(node);
- }
-
- function computeExpressionScopedAllocResult(node) {
- allocResult(node.expression, function() { computeExpressionScoped(node); });
- }
-
- function computeExpressionScopedReuseResultSavePos(node) {
- savePos(node, function() { computeExpressionScopedReuseResult(node); });
- }
-
- function computeParams(node) {
- node.params = vars.buildParams();
- }
-
- var compute = utils.buildNodeVisitor({
- grammar:
- function(node) {
- utils.each(node.rules, compute);
- },
-
- rule:
- function(node) {
- registers.reset();
- computeExpressionScopedAllocResult(node);
- node.registerCount = registers.maxIndex() + 1;
- },
-
- named:
- function(node) {
- reuseResult(node, node.expression);
- compute(node.expression);
- },
-
- choice:
- function(node) {
- utils.each(node.alternatives, function(alternative) {
- reuseResult(node, alternative);
- scoped(function() {
- compute(alternative);
- });
- });
- },
-
- action:
- function(node) {
- savePos(node, function() {
- reuseResult(node, node.expression);
- scoped(function() {
- compute(node.expression);
- computeParams(node);
- });
- });
- },
-
- sequence:
- function(node) {
- savePos(node, function() {
- utils.each(node.elements, function(element) {
- element.resultIndex = registers.alloc();
- compute(element);
- });
- utils.each(node.elements, function(element) {
- registers.release(element.resultIndex);
- });
- });
- },
-
- labeled:
- function(node) {
- vars.add(node.label, node.resultIndex);
- computeExpressionScopedReuseResult(node);
- },
-
- text: computeExpressionScopedReuseResultSavePos,
- simple_and: computeExpressionScopedReuseResultSavePos,
- simple_not: computeExpressionScopedReuseResultSavePos,
- semantic_and: computeParams,
- semantic_not: computeParams,
- optional: computeExpressionScopedReuseResult,
- zero_or_more: computeExpressionScopedAllocResult,
- one_or_more: computeExpressionScopedAllocResult,
- rule_ref: nop,
- literal: nop,
- "class": nop,
- any: nop
- });
-
- compute(ast);
-};
diff --git a/lib/compiler/passes/generate-bytecode.js b/lib/compiler/passes/generate-bytecode.js
new file mode 100644
index 0000000..3d4cf52
--- /dev/null
+++ b/lib/compiler/passes/generate-bytecode.js
@@ -0,0 +1,594 @@
+var utils = require("../../utils"),
+ op = require("../opcodes");
+
+/* Generates bytecode.
+ *
+ * Instructions
+ * ============
+ *
+ * Stack Manipulation
+ * ------------------
+ *
+ * [0] PUSH c
+ *
+ * stack.push(consts[c]);
+ *
+ * [1] PUSH_CURR_POS
+ *
+ * stack.push(currPos);
+ *
+ * [2] POP
+ *
+ * stack.pop();
+ *
+ * [3] POP_CURR_POS
+ *
+ * currPos = stack.pop();
+ *
+ * [4] POP_N n
+ *
+ * stack.pop(n);
+ *
+ * [5] NIP
+ *
+ * value = stack.pop();
+ * stack.pop();
+ * stack.push(value);
+ *
+ * [6] NIP_CURR_POS
+ *
+ * value = stack.pop();
+ * currPos = stack.pop();
+ * stack.push(value);
+ *
+ * [8] APPEND
+ *
+ * value = stack.pop();
+ * array = stack.pop();
+ * array.push(value);
+ * stack.push(array);
+ *
+ * [9] WRAP n
+ *
+ * stack.push(stack.pop(n));
+ *
+ * [10] TEXT
+ *
+ * stack.pop();
+ * stack.push(input.substring(stack.top(), currPos));
+ *
+ * Conditions and Loops
+ * --------------------
+ *
+ * [11] IF t, f
+ *
+ * if (stack.top()) {
+ * interpret(ip + 3, ip + 3 + t);
+ * } else {
+ * interpret(ip + 3 + t, ip + 3 + t + f);
+ * }
+ *
+ * [12] IF_ERROR t, f
+ *
+ * if (stack.top() === null) {
+ * interpret(ip + 3, ip + 3 + t);
+ * } else {
+ * interpret(ip + 3 + t, ip + 3 + t + f);
+ * }
+ *
+ * [13] IF_NOT_ERROR t, f
+ *
+ * if (stack.top() !== null) {
+ * interpret(ip + 3, ip + 3 + t);
+ * } else {
+ * interpret(ip + 3 + t, ip + 3 + t + f);
+ * }
+ *
+ * [14] WHILE_NOT_ERROR b
+ *
+ * while(stack.top() !== null) {
+ * interpret(ip + 2, ip + 2 + b);
+ * }
+ *
+ * Matching
+ * --------
+ *
+ * [15] MATCH_ANY a, f, ...
+ *
+ * if (input.length > currPos) {
+ * interpret(ip + 3, ip + 3 + a);
+ * } else {
+ * interpret(ip + 3 + a, ip + 3 + a + f);
+ * }
+ *
+ * [16] 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);
+ * }
+ *
+ * [17] 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);
+ * }
+ *
+ * [18] 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);
+ * }
+ *
+ * [19] ACCEPT_N n
+ *
+ * stack.push(input.substring(currPos, n));
+ * currPos += n;
+ *
+ * [20] ACCEPT_STRING s
+ *
+ * stack.push(consts[s]);
+ * currPos += consts[s].length;
+ *
+ * [21] FAIL e
+ *
+ * stack.push(null);
+ * fail(consts[e]);
+ *
+ * Calls
+ * -----
+ *
+ * [22] REPORT_SAVED_POS p
+ *
+ * reportedPos = stack[p];
+ *
+ * [23] REPORT_CURR_POS
+ *
+ * reportedPos = currPos;
+ *
+ * [25] CALL f, n, pc, p1, p2, ..., pN
+ *
+ * value = consts[f](stack[p1], ..., stack[pN]);
+ * stack.pop(n);
+ * stack.push(value);
+ *
+ * Rules
+ * -----
+ *
+ * [26] RULE r
+ *
+ * stack.push(parseRule(r));
+ *
+ * Failure Reporting
+ * -----------------
+ *
+ * [27] SILENT_FAILS_ON
+ *
+ * silentFails++;
+ *
+ * [28] SILENT_FAILS_OFF
+ *
+ * silentFails--;
+ */
+module.exports = function(ast, options) {
+ var consts = [];
+
+ function addConst(value) {
+ var index = utils.indexOf(consts, function(c) { return c === 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 = utils.map( utils.values(env), function(p) { return sp - p; });
+
+ return [op.CALL, functionIndex, delta, params.length].concat(params);
+ }
+
+ function buildSimplePredicate(expression, negative, context) {
+ var emptyStringIndex = addConst('""'),
+ nullIndex = addConst('null');
+
+ return buildSequence(
+ [op.PUSH_CURR_POS],
+ [op.SILENT_FAILS_ON],
+ generate(expression, {
+ sp: context.sp + 1,
+ 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, emptyStringIndex]
+ ),
+ buildSequence(
+ [op.POP],
+ [negative ? op.POP_CURR_POS : op.POP],
+ [op.PUSH, nullIndex]
+ )
+ )
+ );
+ }
+
+ function buildSemanticPredicate(code, negative, context) {
+ var functionIndex = addFunctionConst(utils.keys(context.env), code),
+ emptyStringIndex = addConst('""'),
+ nullIndex = addConst('null');
+
+ return buildSequence(
+ [op.REPORT_CURR_POS],
+ buildCall(functionIndex, 0, context.env, context.sp),
+ buildCondition(
+ [op.IF],
+ buildSequence(
+ [op.POP],
+ [op.PUSH, negative ? nullIndex : emptyStringIndex]
+ ),
+ buildSequence(
+ [op.POP],
+ [op.PUSH, negative ? emptyStringIndex : nullIndex]
+ )
+ )
+ );
+ }
+
+ function buildAppendLoop(expressionCode) {
+ return buildLoop(
+ [op.WHILE_NOT_ERROR],
+ buildSequence([op.APPEND], expressionCode)
+ );
+ }
+
+ var generate = utils.buildNodeVisitor({
+ grammar: function(node) {
+ utils.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(utils.quote(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: { },
+ 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 = { },
+ 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(utils.keys(env), node.code);
+
+ return emitCall
+ ? buildSequence(
+ [op.PUSH_CURR_POS],
+ expressionCode,
+ buildCondition(
+ [op.IF_NOT_ERROR],
+ buildSequence(
+ [op.REPORT_SAVED_POS, 1],
+ buildCall(functionIndex, 1, env, context.sp + 2)
+ ),
+ []
+ ),
+ buildCondition([op.IF_ERROR], [op.NIP_CURR_POS], [op.NIP])
+ )
+ : expressionCode;
+ },
+
+ sequence: function(node, context) {
+ var emptyArrayIndex, nullIndex;
+
+ function buildElementsCode(elements, context) {
+ var processedCount, functionIndex;
+
+ if (elements.length > 0) {
+ processedCount = node.elements.length - elements.slice(1).length;
+
+ return buildSequence(
+ generate(elements[0], context),
+ 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, nullIndex]
+ )
+ )
+ );
+ } else {
+ if (context.action) {
+ functionIndex = addFunctionConst(
+ utils.keys(context.env),
+ context.action.code
+ );
+
+ return buildSequence(
+ [op.REPORT_SAVED_POS, node.elements.length],
+ buildCall(
+ functionIndex,
+ node.elements.length,
+ context.env,
+ context.sp
+ ),
+ buildCondition([op.IF_ERROR], [op.NIP_CURR_POS], [op.NIP])
+ );
+ } else {
+ return buildSequence([op.WRAP, node.elements.length], [op.NIP]);
+ }
+ }
+ }
+
+ if (node.elements.length > 0) {
+ nullIndex = addConst('null');
+
+ return buildSequence(
+ [op.PUSH_CURR_POS],
+ buildElementsCode(node.elements, {
+ sp: context.sp + 1,
+ env: context.env,
+ action: context.action
+ })
+ );
+ } else {
+ emptyArrayIndex = addConst('[]');
+
+ return [op.PUSH, emptyArrayIndex];
+ }
+ },
+
+ labeled: function(node, context) {
+ context.env[node.label] = context.sp + 1;
+
+ return generate(node.expression, {
+ sp: context.sp,
+ env: { },
+ action: null
+ });
+ },
+
+ text: function(node, context) {
+ return buildSequence(
+ [op.PUSH_CURR_POS],
+ generate(node.expression, {
+ sp: context.sp + 1,
+ env: { },
+ action: null
+ }),
+ buildCondition([op.IF_NOT_ERROR], [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);
+ },
+
+ semantic_and: function(node, context) {
+ return buildSemanticPredicate(node.code, false, context);
+ },
+
+ semantic_not: function(node, context) {
+ return buildSemanticPredicate(node.code, true, context);
+ },
+
+ optional: function(node, context) {
+ var emptyStringIndex = addConst('""');
+
+ return buildSequence(
+ generate(node.expression, {
+ sp: context.sp,
+ env: { },
+ action: null
+ }),
+ buildCondition(
+ [op.IF_ERROR],
+ buildSequence([op.POP], [op.PUSH, emptyStringIndex]),
+ []
+ )
+ );
+ },
+
+ zero_or_more: function(node, context) {
+ var emptyArrayIndex = addConst('[]');
+ expressionCode = generate(node.expression, {
+ sp: context.sp + 1,
+ env: { },
+ action: null
+ });
+
+ return buildSequence(
+ [op.PUSH, emptyArrayIndex],
+ expressionCode,
+ buildAppendLoop(expressionCode),
+ [op.POP]
+ );
+ },
+
+ one_or_more: function(node, context) {
+ var emptyArrayIndex = addConst('[]');
+ nullIndex = addConst('null');
+ expressionCode = generate(node.expression, {
+ sp: context.sp + 1,
+ env: { },
+ action: null
+ });
+
+ return buildSequence(
+ [op.PUSH, emptyArrayIndex],
+ expressionCode,
+ buildCondition(
+ [op.IF_NOT_ERROR],
+ buildSequence(buildAppendLoop(expressionCode), [op.POP]),
+ buildSequence([op.POP], [op.POP], [op.PUSH, nullIndex])
+ )
+ );
+ },
+
+ rule_ref: function(node) {
+ return [op.RULE, utils.indexOfRuleByName(ast, node.name)];
+ },
+
+ literal: function(node) {
+ var stringIndex, expectedIndex;
+
+ if (node.value.length > 0) {
+ stringIndex = addConst(node.ignoreCase
+ ? utils.quote(node.value.toLowerCase())
+ : utils.quote(node.value)
+ );
+ expectedIndex = addConst(utils.quote(utils.quote(node.value)));
+
+ /*
+ * 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, regexpIndex, expectedIndex;
+
+ if (node.parts.length > 0) {
+ regexp = '/^['
+ + (node.inverted ? '^' : '')
+ + utils.map(node.parts, function(part) {
+ return part instanceof Array
+ ? utils.quoteForRegexpClass(part[0])
+ + '-'
+ + utils.quoteForRegexpClass(part[1])
+ : utils.quoteForRegexpClass(part);
+ }).join('')
+ + ']/' + (node.ignoreCase ? 'i' : '');
+ } else {
+ /*
+ * IE considers regexps /[]/ and /[^]/ as syntactically invalid, so we
+ * translate them into euqivalents it can handle.
+ */
+ regexp = node.inverted ? '/^[\\S\\s]/' : '/^(?!)/';
+ }
+
+ regexpIndex = addConst(regexp);
+ expectedIndex = addConst(utils.quote(node.rawText));
+
+ return buildCondition(
+ [op.MATCH_REGEXP, regexpIndex],
+ [op.ACCEPT_N, 1],
+ [op.FAIL, expectedIndex]
+ );
+ },
+
+ any: function(node) {
+ var expectedIndex = addConst(utils.quote("any character"));
+
+ return buildCondition(
+ [op.MATCH_ANY],
+ [op.ACCEPT_N, 1],
+ [op.FAIL, expectedIndex]
+ );
+ }
+ });
+
+ generate(ast);
+};
diff --git a/lib/compiler/passes/generate-code.js b/lib/compiler/passes/generate-code.js
deleted file mode 100644
index a858570..0000000
--- a/lib/compiler/passes/generate-code.js
+++ /dev/null
@@ -1,867 +0,0 @@
-var utils = require("../../utils");
-
-/* Generates the parser code. */
-module.exports = function(ast, options) {
- options = utils.clone(options);
- utils.defaults(options, {
- cache: false,
- allowedStartRules: [ast.startRule]
- });
-
- /*
- * Codie 1.1.0
- *
- * https://github.com/dmajda/codie
- *
- * Copyright (c) 2011-2012 David Majda
- * Licensend under the MIT license.
- */
- var Codie = (function(undefined) {
-
- function stringEscape(s) {
- function hex(ch) { return ch.charCodeAt(0).toString(16).toUpperCase(); }
-
- /*
- * ECMA-262, 5th ed., 7.8.4: All characters may appear literally in a
- * string literal except for the closing quote character, backslash,
- * carriage return, line separator, paragraph separator, and line feed.
- * Any character may appear in the form of an escape sequence.
- *
- * For portability, we also escape escape all control and non-ASCII
- * characters. Note that "\0" and "\v" escape sequences are not used
- * because JSHint does not like the first and IE the second.
- */
- return s
- .replace(/\\/g, '\\\\') // backslash
- .replace(/"/g, '\\"') // closing double quote
- .replace(/\x08/g, '\\b') // backspace
- .replace(/\t/g, '\\t') // horizontal tab
- .replace(/\n/g, '\\n') // line feed
- .replace(/\f/g, '\\f') // form feed
- .replace(/\r/g, '\\r') // carriage return
- .replace(/[\x00-\x07\x0B\x0E\x0F]/g, function(ch) { return '\\x0' + hex(ch); })
- .replace(/[\x10-\x1F\x80-\xFF]/g, function(ch) { return '\\x' + hex(ch); })
- .replace(/[\u0180-\u0FFF]/g, function(ch) { return '\\u0' + hex(ch); })
- .replace(/[\u1080-\uFFFF]/g, function(ch) { return '\\u' + hex(ch); });
- }
-
- function push(s) { return '__p.push(' + s + ');'; }
-
- function pushRaw(template, length, state) {
- function unindent(code, level, unindentFirst) {
- return code.replace(
- new RegExp('^.{' + level +'}', "gm"),
- function(str, offset) {
- if (offset === 0) {
- return unindentFirst ? '' : str;
- } else {
- return "";
- }
- }
- );
- }
-
- var escaped = stringEscape(unindent(
- template.substring(0, length),
- state.indentLevel(),
- state.atBOL
- ));
-
- return escaped.length > 0 ? push('"' + escaped + '"') : '';
- }
-
-
- var Codie = {
- /* Codie version (uses semantic versioning). */
- VERSION: "1.1.0",
-
- /*
- * Specifies by how many characters do #if/#else and #for unindent their
- * content in the generated code.
- */
- indentStep: 2,
-
- /* Description of #-commands. Extend to define your own commands. */
- commands: {
- "if": {
- params: /^(.*)$/,
- compile: function(state, prefix, params) {
- return ['if(' + params[0] + '){', []];
- },
- stackOp: "push"
- },
- "else": {
- params: /^$/,
- compile: function(state) {
- var stack = state.commandStack,
- insideElse = stack[stack.length - 1] === "else",
- insideIf = stack[stack.length - 1] === "if";
-
- if (insideElse) { throw new Error("Multiple #elses."); }
- if (!insideIf) { throw new Error("Using #else outside of #if."); }
-
- return ['}else{', []];
- },
- stackOp: "replace"
- },
- "for": {
- params: /^([a-zA-Z_][a-zA-Z0-9_]*)[ \t]+in[ \t]+(.*)$/,
- init: function(state) {
- state.forCurrLevel = 0; // current level of #for loop nesting
- state.forMaxLevel = 0; // maximum level of #for loop nesting
- },
- compile: function(state, prefix, params) {
- var c = '__c' + state.forCurrLevel, // __c for "collection"
- l = '__l' + state.forCurrLevel, // __l for "length"
- i = '__i' + state.forCurrLevel; // __i for "index"
-
- state.forCurrLevel++;
- if (state.forMaxLevel < state.forCurrLevel) {
- state.forMaxLevel = state.forCurrLevel;
- }
-
- return [
- c + '=' + params[1] + ';'
- + l + '=' + c + '.length;'
- + 'for(' + i + '=0;' + i + '<' + l + ';' + i + '++){'
- + params[0] + '=' + c + '[' + i + '];',
- [params[0], c, l, i]
- ];
- },
- exit: function(state) { state.forCurrLevel--; },
- stackOp: "push"
- },
- "end": {
- params: /^$/,
- compile: function(state) {
- var stack = state.commandStack, exit;
-
- if (stack.length === 0) { throw new Error("Too many #ends."); }
-
- exit = Codie.commands[stack[stack.length - 1]].exit;
- if (exit) { exit(state); }
-
- return ['}', []];
- },
- stackOp: "pop"
- },
- "block": {
- params: /^(.*)$/,
- compile: function(state, prefix, params) {
- var x = '__x', // __x for "prefix",
- n = '__n', // __n for "lines"
- l = '__l', // __l for "length"
- i = '__i'; // __i for "index"
-
- /*
- * Originally, the generated code used |String.prototype.replace|, but
- * it is buggy in certain versions of V8 so it was rewritten. See the
- * tests for details.
- */
- return [
- x + '="' + stringEscape(prefix.substring(state.indentLevel())) + '";'
- + n + '=(' + params[0] + ').toString().split("\\n");'
- + l + '=' + n + '.length;'
- + 'for(' + i + '=0;' + i + '<' + l + ';' + i + '++){'
- + n + '[' + i +']=' + x + '+' + n + '[' + i + ']+"\\n";'
- + '}'
- + push(n + '.join("")'),
- [x, n, l, i]
- ];
- },
- stackOp: "nop"
- }
- },
-
- /*
- * Compiles a template into a function. When called, this function will
- * execute the template in the context of an object passed in a parameter and
- * return the result.
- */
- template: function(template) {
- var stackOps = {
- push: function(stack, name) { stack.push(name); },
- replace: function(stack, name) { stack[stack.length - 1] = name; },
- pop: function(stack) { stack.pop(); },
- nop: function() { }
- };
-
- function compileExpr(state, expr) {
- state.atBOL = false;
- return [push(expr), []];
- }
-
- function compileCommand(state, prefix, name, params) {
- var command, match, result;
-
- command = Codie.commands[name];
- if (!command) { throw new Error("Unknown command: #" + name + "."); }
-
- match = command.params.exec(params);
- if (match === null) {
- throw new Error(
- "Invalid params for command #" + name + ": " + params + "."
- );
- }
-
- result = command.compile(state, prefix, match.slice(1));
- stackOps[command.stackOp](state.commandStack, name);
- state.atBOL = true;
- return result;
- }
-
- var state = { // compilation state
- commandStack: [], // stack of commands as they were nested
- atBOL: true, // is the next character to process at BOL?
- indentLevel: function() {
- return Codie.indentStep * this.commandStack.length;
- }
- },
- code = '', // generated template function code
- vars = ['__p=[]'], // variables used by generated code
- name, match, result, i;
-
- /* Initialize state. */
- for (name in Codie.commands) {
- if (Codie.commands[name].init) { Codie.commands[name].init(state); }
- }
-
- /* Compile the template. */
- while ((match = /^([ \t]*)#([a-zA-Z_][a-zA-Z0-9_]*)(?:[ \t]+([^ \t\n][^\n]*))?[ \t]*(?:\n|$)|#\{([^}]*)\}/m.exec(template)) !== null) {
- code += pushRaw(template, match.index, state);
- result = match[2] !== undefined && match[2] !== ""
- ? compileCommand(state, match[1], match[2], match[3] || "") // #-command
- : compileExpr(state, match[4]); // #{...}
- code += result[0];
- vars = vars.concat(result[1]);
- template = template.substring(match.index + match[0].length);
- }
- code += pushRaw(template, template.length, state);
-
- /* Check the final state. */
- if (state.commandStack.length > 0) { throw new Error("Missing #end."); }
-
- /* Sanitize the list of variables used by commands. */
- vars.sort();
- for (i = 0; i < vars.length; i++) {
- if (vars[i] === vars[i - 1]) { vars.splice(i--, 1); }
- }
-
- /* Create the resulting function. */
- return new Function("__v", [
- '__v=__v||{};',
- 'var ' + vars.join(',') + ';',
- 'with(__v){',
- code,
- 'return __p.join("").replace(/^\\n+|\\n+$/g,"");};'
- ].join(''));
- }
- };
-
- return Codie;
-
- })();
-
- var templates = (function() {
- var name,
- templates = {},
- sources = {
- grammar: [
- '(function(){',
- ' /*',
- ' * Generated by PEG.js 0.7.0.',
- ' *',
- ' * http://pegjs.majda.cz/',
- ' */',
- ' ',
- /* This needs to be in sync with |subclass| in utils.js. */
- ' function subclass(child, parent) {',
- ' function ctor() { this.constructor = child; }',
- ' ctor.prototype = parent.prototype;',
- ' child.prototype = new ctor();',
- ' }',
- ' ',
- /* This needs to be in sync with |quote| in utils.js. */
- ' function quote(s) {',
- ' /*',
- ' * ECMA-262, 5th ed., 7.8.4: All characters may appear literally in a',
- ' * string literal except for the closing quote character, backslash,',
- ' * carriage return, line separator, paragraph separator, and line feed.',
- ' * Any character may appear in the form of an escape sequence.',
- ' *',
- ' * For portability, we also escape escape all control and non-ASCII',
- ' * characters. Note that "\\0" and "\\v" escape sequences are not used',
- ' * because JSHint does not like the first and IE the second.',
- ' */',
- ' return \'"\' + s',
- ' .replace(/\\\\/g, \'\\\\\\\\\') // backslash',
- ' .replace(/"/g, \'\\\\"\') // closing quote character',
- ' .replace(/\\x08/g, \'\\\\b\') // backspace',
- ' .replace(/\\t/g, \'\\\\t\') // horizontal tab',
- ' .replace(/\\n/g, \'\\\\n\') // line feed',
- ' .replace(/\\f/g, \'\\\\f\') // form feed',
- ' .replace(/\\r/g, \'\\\\r\') // carriage return',
- ' .replace(/[\\x00-\\x07\\x0B\\x0E-\\x1F\\x80-\\uFFFF]/g, escape)',
- ' + \'"\';',
- ' }',
- ' ',
- ' var result = {',
- ' /*',
- ' * Parses the input with a generated parser. If the parsing is successful,',
- ' * returns a value explicitly or implicitly specified by the grammar from',
- ' * which the parser was generated (see |PEG.buildParser|). If the parsing is',
- ' * unsuccessful, throws |PEG.parser.SyntaxError| describing the error.',
- ' */',
- ' parse: function(input) {',
- ' var parseFunctions = {',
- ' #for rule in options.allowedStartRules',
- ' #{string(rule) + ": parse_" + rule + (rule !== options.allowedStartRules[options.allowedStartRules.length - 1] ? "," : "")}',
- ' #end',
- ' };',
- ' ',
- ' var options = arguments.length > 1 ? arguments[1] : {},',
- ' startRule;',
- ' ',
- ' if (options.startRule !== undefined) {',
- ' startRule = options.startRule;',
- ' ',
- ' if (parseFunctions[startRule] === undefined) {',
- ' throw new Error("Can\'t start parsing from rule " + quote(startRule) + ".");',
- ' }',
- ' } else {',
- ' startRule = #{string(options.allowedStartRules[0])};',
- ' }',
- ' ',
- ' var pos = 0;',
- ' var reportedPos = 0;',
- ' var cachedReportedPos = 0;',
- ' var cachedReportedPosDetails = { line: 1, column: 1, seenCR: false };',
- ' var reportFailures = 0;', // 0 = report, anything > 0 = do not report
- ' var rightmostFailuresPos = 0;',
- ' var rightmostFailuresExpected = [];',
- ' #if options.cache',
- ' var cache = {};',
- ' #end',
- ' ',
- /* This needs to be in sync with |padLeft| in utils.js. */
- ' function padLeft(input, padding, length) {',
- ' var result = input;',
- ' ',
- ' var padLength = length - input.length;',
- ' for (var i = 0; i < padLength; i++) {',
- ' result = padding + result;',
- ' }',
- ' ',
- ' return result;',
- ' }',
- ' ',
- /* This needs to be in sync with |escape| in utils.js. */
- ' function escape(ch) {',
- ' var charCode = ch.charCodeAt(0);',
- ' var escapeChar;',
- ' var length;',
- ' ',
- ' if (charCode <= 0xFF) {',
- ' escapeChar = \'x\';',
- ' length = 2;',
- ' } else {',
- ' escapeChar = \'u\';',
- ' length = 4;',
- ' }',
- ' ',
- ' return \'\\\\\' + escapeChar + padLeft(charCode.toString(16).toUpperCase(), \'0\', length);',
- ' }',
- ' ',
- ' function computeReportedPosDetails() {',
- ' function advanceCachedReportedPos() {',
- ' var ch;',
- ' ',
- ' for (; cachedReportedPos < reportedPos; cachedReportedPos++) {',
- ' ch = input.charAt(cachedReportedPos);',
- ' if (ch === "\\n") {',
- ' if (!cachedReportedPosDetails.seenCR) { cachedReportedPosDetails.line++; }',
- ' cachedReportedPosDetails.column = 1;',
- ' cachedReportedPosDetails.seenCR = false;',
- ' } else if (ch === "\\r" || ch === "\\u2028" || ch === "\\u2029") {',
- ' cachedReportedPosDetails.line++;',
- ' cachedReportedPosDetails.column = 1;',
- ' cachedReportedPosDetails.seenCR = true;',
- ' } else {',
- ' cachedReportedPosDetails.column++;',
- ' cachedReportedPosDetails.seenCR = false;',
- ' }',
- ' }',
- ' }',
- ' ',
- ' if (cachedReportedPos !== reportedPos) {',
- ' if (cachedReportedPos > reportedPos) {',
- ' cachedReportedPos = 0;',
- ' cachedReportedPosDetails = { line: 1, column: 1, seenCR: false };',
- ' }',
- ' advanceCachedReportedPos();',
- ' }',
- ' ',
- ' return cachedReportedPosDetails;',
- ' }',
- ' ',
- ' function text() {',
- ' return input.substring(reportedPos, pos);',
- ' }',
- ' ',
- ' function offset() {',
- ' return reportedPos;',
- ' }',
- ' ',
- ' function line() {',
- ' return computeReportedPosDetails().line;',
- ' }',
- ' ',
- ' function column() {',
- ' return computeReportedPosDetails().column;',
- ' }',
- ' ',
- ' function matchFailed(failure) {',
- ' if (pos < rightmostFailuresPos) {',
- ' return;',
- ' }',
- ' ',
- ' if (pos > rightmostFailuresPos) {',
- ' rightmostFailuresPos = pos;',
- ' rightmostFailuresExpected = [];',
- ' }',
- ' ',
- ' rightmostFailuresExpected.push(failure);',
- ' }',
- ' ',
- ' #for rule in node.rules',
- ' #block emit(rule)',
- ' ',
- ' #end',
- ' ',
- ' function cleanupExpected(expected) {',
- ' expected.sort();',
- ' ',
- ' var lastExpected = null;',
- ' var cleanExpected = [];',
- ' for (var i = 0; i < expected.length; i++) {',
- ' if (expected[i] !== lastExpected) {',
- ' cleanExpected.push(expected[i]);',
- ' lastExpected = expected[i];',
- ' }',
- ' }',
- ' return cleanExpected;',
- ' }',
- ' ',
- ' #if node.initializer',
- ' #block emit(node.initializer)',
- ' #end',
- ' ',
- ' var result = parseFunctions[startRule]();',
- ' ',
- ' /*',
- ' * The parser is now in one of the following three states:',
- ' *',
- ' * 1. The parser successfully parsed the whole input.',
- ' *',
- ' * - |result !== null|',
- ' * - |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) {',
- ' reportedPos = Math.max(pos, rightmostFailuresPos);',
- ' var found = reportedPos < input.length ? input.charAt(reportedPos) : null;',
- ' var reportedPosDetails = computeReportedPosDetails();',
- ' ',
- ' throw new this.SyntaxError(',
- ' cleanupExpected(rightmostFailuresExpected),',
- ' found,',
- ' reportedPos,',
- ' reportedPosDetails.line,',
- ' reportedPosDetails.column',
- ' );',
- ' }',
- ' ',
- ' return result;',
- ' }',
- ' };',
- ' ',
- ' /* Thrown when a parser encounters a syntax error. */',
- ' ',
- ' result.SyntaxError = function(expected, found, offset, line, column) {',
- ' function buildMessage(expected, found) {',
- ' var expectedHumanized, foundHumanized;',
- ' ',
- ' switch (expected.length) {',
- ' case 0:',
- ' expectedHumanized = "end of input";',
- ' break;',
- ' case 1:',
- ' expectedHumanized = expected[0];',
- ' break;',
- ' default:',
- ' expectedHumanized = expected.slice(0, expected.length - 1).join(", ")',
- ' + " or "',
- ' + expected[expected.length - 1];',
- ' }',
- ' ',
- ' foundHumanized = found ? quote(found) : "end of input";',
- ' ',
- ' return "Expected " + expectedHumanized + " but " + foundHumanized + " found.";',
- ' }',
- ' ',
- ' this.name = "SyntaxError";',
- ' this.expected = expected;',
- ' this.found = found;',
- ' this.message = buildMessage(expected, found);',
- ' this.offset = offset;',
- ' this.line = line;',
- ' this.column = column;',
- ' };',
- ' ',
- ' subclass(result.SyntaxError, Error);',
- ' ',
- ' return result;',
- '})()'
- ],
- rule: [
- 'function parse_#{node.name}() {',
- ' #if options.cache',
- ' var cacheKey = "#{node.name}@" + pos;',
- ' var cachedResult = cache[cacheKey];',
- ' if (cachedResult) {',
- ' pos = cachedResult.nextPos;',
- ' return cachedResult.result;',
- ' }',
- ' ',
- ' #end',
- ' #if node.registerCount > 0',
- ' var #{map(range(node.registerCount), r).join(", ")};',
- ' #end',
- ' ',
- ' #block emit(node.expression)',
- ' #if options.cache',
- ' ',
- ' cache[cacheKey] = {',
- ' nextPos: pos,',
- ' result: #{r(node.expression.resultIndex)}',
- ' };',
- ' #end',
- ' return #{r(node.expression.resultIndex)};',
- '}'
- ],
- named: [
- 'reportFailures++;',
- '#block emit(node.expression)',
- 'reportFailures--;',
- 'if (reportFailures === 0 && #{r(node.resultIndex)} === null) {',
- ' matchFailed(#{string(node.name)});',
- '}'
- ],
- choice: [
- '#block emit(alternative)',
- '#block nextAlternativesCode'
- ],
- "choice.next": [
- 'if (#{r(node.resultIndex)} === null) {',
- ' #block code',
- '}'
- ],
- action: [
- '#{r(node.posIndex)} = pos;',
- '#block emit(node.expression)',
- 'if (#{r(node.resultIndex)} !== null) {',
- ' reportedPos = #{r(node.posIndex)};',
- ' #{r(node.resultIndex)} = (function(#{keys(node.params).join(", ")}) {#{node.code}})(#{map(values(node.params), r).join(", ")});',
- '}',
- 'if (#{r(node.resultIndex)} === null) {',
- ' pos = #{r(node.posIndex)};',
- '}'
- ],
- sequence: [
- '#{r(node.posIndex)} = pos;',
- '#block code'
- ],
- "sequence.iteration": [
- '#block emit(element)',
- 'if (#{r(element.resultIndex)} !== null) {',
- ' #block code',
- '} else {',
- ' #{r(node.resultIndex)} = null;',
- ' pos = #{r(node.posIndex)};',
- '}'
- ],
- "sequence.inner": [
- '#{r(node.resultIndex)} = [#{map(pluck(node.elements, "resultIndex"), r).join(", ")}];'
- ],
- text: [
- '#{r(node.posIndex)} = pos;',
- '#block emit(node.expression)',
- 'if (#{r(node.resultIndex)} !== null) {',
- ' #{r(node.resultIndex)} = input.substring(pos, #{r(node.posIndex)});',
- '}'
- ],
- simple_and: [
- '#{r(node.posIndex)} = pos;',
- 'reportFailures++;',
- '#block emit(node.expression)',
- 'reportFailures--;',
- 'if (#{r(node.resultIndex)} !== null) {',
- ' #{r(node.resultIndex)} = "";',
- ' pos = #{r(node.posIndex)};',
- '} else {',
- ' #{r(node.resultIndex)} = null;',
- '}'
- ],
- simple_not: [
- '#{r(node.posIndex)} = pos;',
- 'reportFailures++;',
- '#block emit(node.expression)',
- 'reportFailures--;',
- 'if (#{r(node.resultIndex)} === null) {',
- ' #{r(node.resultIndex)} = "";',
- '} else {',
- ' #{r(node.resultIndex)} = null;',
- ' pos = #{r(node.posIndex)};',
- '}'
- ],
- semantic_and: [
- 'reportedPos = pos;',
- '#{r(node.resultIndex)} = (function(#{keys(node.params).join(", ")}) {#{node.code}})(#{map(values(node.params), r).join(", ")}) ? "" : null;'
- ],
- semantic_not: [
- 'reportedPos = pos;',
- '#{r(node.resultIndex)} = (function(#{keys(node.params).join(", ")}) {#{node.code}})(#{map(values(node.params), r).join(", ")}) ? null : "";'
- ],
- optional: [
- '#block emit(node.expression)',
- '#{r(node.resultIndex)} = #{r(node.resultIndex)} !== null ? #{r(node.resultIndex)} : "";'
- ],
- zero_or_more: [
- '#{r(node.resultIndex)} = [];',
- '#block emit(node.expression)',
- 'while (#{r(node.expression.resultIndex)} !== null) {',
- ' #{r(node.resultIndex)}.push(#{r(node.expression.resultIndex)});',
- ' #block emit(node.expression)',
- '}'
- ],
- one_or_more: [
- '#block emit(node.expression)',
- 'if (#{r(node.expression.resultIndex)} !== null) {',
- ' #{r(node.resultIndex)} = [];',
- ' while (#{r(node.expression.resultIndex)} !== null) {',
- ' #{r(node.resultIndex)}.push(#{r(node.expression.resultIndex)});',
- ' #block emit(node.expression)',
- ' }',
- '} else {',
- ' #{r(node.resultIndex)} = null;',
- '}'
- ],
- rule_ref: [
- '#{r(node.resultIndex)} = parse_#{node.name}();'
- ],
- literal: [
- '#if node.value.length === 0',
- ' #{r(node.resultIndex)} = "";',
- '#else',
- ' #if !node.ignoreCase',
- ' #if node.value.length === 1',
- ' if (input.charCodeAt(pos) === #{node.value.charCodeAt(0)}) {',
- ' #else',
- ' if (input.substr(pos, #{node.value.length}) === #{string(node.value)}) {',
- ' #end',
- ' #else',
- /*
- * One-char literals are not optimized when case-insensitive
- * matching is enabled. This is because there is no simple way to
- * lowercase a character code that works for character outside ASCII
- * letters. Moreover, |toLowerCase| can change string length,
- * meaning the result of lowercasing a character can be more
- * characters.
- */
- ' if (input.substr(pos, #{node.value.length}).toLowerCase() === #{string(node.value.toLowerCase())}) {',
- ' #end',
- ' #if !node.ignoreCase',
- ' #{r(node.resultIndex)} = #{string(node.value)};',
- ' #else',
- ' #{r(node.resultIndex)} = input.substr(pos, #{node.value.length});',
- ' #end',
- ' #{node.value.length > 1 ? "pos += " + node.value.length : "pos++"};',
- ' } else {',
- ' #{r(node.resultIndex)} = null;',
- ' if (reportFailures === 0) {',
- ' matchFailed(#{string(string(node.value))});',
- ' }',
- ' }',
- '#end'
- ],
- "class": [
- 'if (#{regexp}.test(input.charAt(pos))) {',
- ' #{r(node.resultIndex)} = input.charAt(pos);',
- ' pos++;',
- '} else {',
- ' #{r(node.resultIndex)} = null;',
- ' if (reportFailures === 0) {',
- ' matchFailed(#{string(node.rawText)});',
- ' }',
- '}'
- ],
- any: [
- 'if (input.length > pos) {',
- ' #{r(node.resultIndex)} = input.charAt(pos);',
- ' pos++;',
- '} else {',
- ' #{r(node.resultIndex)} = null;',
- ' if (reportFailures === 0) {',
- ' matchFailed("any character");',
- ' }',
- '}'
- ]
- };
-
- for (name in sources) {
- templates[name] = Codie.template(sources[name].join('\n'));
- }
-
- return templates;
- })();
-
- function fill(name, vars) {
- vars.string = utils.quote;
- vars.range = utils.range;
- vars.map = utils.map;
- vars.pluck = utils.pluck;
- vars.keys = utils.keys;
- vars.values = utils.values;
- vars.emit = emit;
- vars.options = options;
-
- vars.r = function(index) { return "r" + index; };
-
- return templates[name](vars);
- }
-
- function emitSimple(name) {
- return function(node) { return fill(name, { node: node }); };
- }
-
- var emit = utils.buildNodeVisitor({
- grammar: emitSimple("grammar"),
-
- initializer: function(node) { return node.code; },
-
- rule: emitSimple("rule"),
-
- /*
- * The contract for all code fragments generated by the following functions
- * is as follows.
- *
- * The code fragment tries to match a part of the input starting with the
- * position indicated in |pos|. That position may point past the end of the
- * input.
- *
- * * If the code fragment matches the input, it advances |pos| to point to
- * the first chracter following the matched part of the input and sets a
- * register with index specified by |node.resultIndex| to an appropriate
- * value. This value is always non-|null|.
- *
- * * If the code fragment does not match the input, it returns with |pos|
- * set to the original value and it sets a register with index specified
- * by |node.posIndex| to |null|.
- *
- * The code uses only registers with indices specified by |node.resultIndex|
- * and |node.posIndex| where |node| is the processed node or some of its
- * subnodes. It does not use any other registers.
- */
-
- named: emitSimple("named"),
-
- choice: function(node) {
- var code, nextAlternativesCode;
-
- for (var i = node.alternatives.length - 1; i >= 0; i--) {
- nextAlternativesCode = i !== node.alternatives.length - 1
- ? fill("choice.next", { node: node, code: code })
- : '';
- code = fill("choice", {
- alternative: node.alternatives[i],
- nextAlternativesCode: nextAlternativesCode
- });
- }
-
- return code;
- },
-
- action: emitSimple("action"),
-
- sequence: function(node) {
- var code = fill("sequence.inner", { node: node });
-
- for (var i = node.elements.length - 1; i >= 0; i--) {
- code = fill("sequence.iteration", {
- node: node,
- element: node.elements[i],
- code: code
- });
- }
-
- return fill("sequence", { node: node, code: code });
- },
-
- labeled: function(node) { return emit(node.expression); },
-
- text: emitSimple("text"),
- simple_and: emitSimple("simple_and"),
- simple_not: emitSimple("simple_not"),
- semantic_and: emitSimple("semantic_and"),
- semantic_not: emitSimple("semantic_not"),
- optional: emitSimple("optional"),
- zero_or_more: emitSimple("zero_or_more"),
- one_or_more: emitSimple("one_or_more"),
- rule_ref: emitSimple("rule_ref"),
- literal: emitSimple("literal"),
-
- "class": function(node) {
- var regexp;
-
- if (node.parts.length > 0) {
- regexp = '/^['
- + (node.inverted ? '^' : '')
- + utils.map(node.parts, function(part) {
- return part instanceof Array
- ? utils.quoteForRegexpClass(part[0])
- + '-'
- + utils.quoteForRegexpClass(part[1])
- : utils.quoteForRegexpClass(part);
- }).join('')
- + ']/' + (node.ignoreCase ? 'i' : '');
- } else {
- /*
- * Stupid IE considers regexps /[]/ and /[^]/ syntactically invalid, so
- * we translate them into euqivalents it can handle.
- */
- regexp = node.inverted ? '/^[\\S\\s]/' : '/^(?!)/';
- }
-
- return fill("class", { node: node, regexp: regexp });
- },
-
- any: emitSimple("any")
- });
-
- ast.code = emit(ast);
-};
diff --git a/lib/compiler/passes/generate-javascript.js b/lib/compiler/passes/generate-javascript.js
new file mode 100644
index 0000000..719c93b
--- /dev/null
+++ b/lib/compiler/passes/generate-javascript.js
@@ -0,0 +1,950 @@
+var utils = require("../../utils"),
+ op = require("../opcodes");
+
+/* Generates parser JavaScript code. */
+module.exports = function(ast, options) {
+ options = utils.clone(options);
+ utils.defaults(options, {
+ cache: false,
+ allowedStartRules: [ast.startRule],
+ optimize: "speed"
+ });
+
+ /* These only indent non-empty lines to avoid trailing whitespace. */
+ function indent2(code) { return code.replace(/^(.+)$/gm, ' $1'); }
+ function indent4(code) { return code.replace(/^(.+)$/gm, ' $1'); }
+ function indent8(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(utils.map(
+ ast.rules,
+ function(rule) {
+ return 'peg$decode('
+ + utils.quote(utils.map(
+ rule.bytecode,
+ function(b) { return String.fromCharCode(b + 32); }
+ ).join(''))
+ + ')';
+ }
+ ).join(',\n')),
+ '],'
+ ].join('\n');
+ } else {
+ return utils.map(
+ ast.consts,
+ function(c, i) { return 'peg$c' + i + ' = ' + c + ','; }
+ ).join('\n');
+ }
+ }
+
+ function generateCacheHeader(ruleIndexCode) {
+ return [
+ 'var key = peg$currPos * ' + ast.rules.length + ' + ' + ruleIndexCode + ',',
+ ' cached = peg$cache[key];',
+ '',
+ 'if (cached) {',
+ ' peg$currPos = cached.nextPos;',
+ ' return cached.result;',
+ '}',
+ ''
+ ].join('\n');
+ }
+
+ function generateCacheFooter(resultCode) {
+ return [
+ '',
+ 'peg$cache[key] = { nextPos: peg$currPos, result: ' + resultCode + ' };'
+ ].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) {',
+ ' var bc = peg$bytecode[index],',
+ ' ip = 0,',
+ ' ips = [],',
+ ' end = bc.length,',
+ ' ends = [],',
+ ' stack = [],',
+ ' params, i;',
+ ''
+ ].join('\n'));
+
+ if (options.cache) {
+ parts.push(indent2(generateCacheHeader('index')));
+ }
+
+ parts.push([
+ ' function protect(object) {',
+ ' return Object.prototype.toString.apply(object) === "[object Array]" ? [] : object;',
+ ' }',
+ '',
+ /*
+ * 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
+ /*
+ * Hack: One of the constants can be an empty array. It needs to be cloned
+ * because it can be modified later on the stack by |APPEND|.
+ */
+ ' stack.push(protect(peg$consts[bc[ip + 1]]));',
+ ' ip += 2;',
+ ' 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.NIP_CURR_POS + ':', // NIP_CURR_POS
+ ' peg$currPos = stack.splice(-2, 1)[0];',
+ ' 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]));',
+ ' ip += 2;',
+ ' break;',
+ '',
+ ' case ' + op.TEXT + ':', // TEXT
+ ' stack.pop();',
+ ' stack.push(input.substring(stack[stack.length - 1], 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] === null',
+ 0
+ )),
+ '',
+ ' case ' + op.IF_NOT_ERROR + ':', // IF_NOT_ERROR t, f
+ indent10(
+ generateCondition('stack[stack.length - 1] !== null',
+ 0
+ )),
+ '',
+ ' case ' + op.WHILE_NOT_ERROR + ':', // WHILE_NOT_ERROR b
+ indent10(generateLoop('stack[stack.length - 1] !== null')),
+ '',
+ ' 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(null);',
+ ' if (peg$silentFails === 0) {',
+ ' peg$fail(peg$consts[bc[ip + 1]]);',
+ ' }',
+ ' ip += 2;',
+ ' break;',
+ '',
+ ' case ' + op.REPORT_SAVED_POS + ':', // REPORT_SAVED_POS p
+ ' peg$reportedPos = stack[stack.length - 1 - bc[ip + 1]];',
+ ' ip += 2;',
+ ' break;',
+ '',
+ ' case ' + op.REPORT_CURR_POS + ':', // REPORT_CURR_POS
+ ' peg$reportedPos = 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'));
+
+ if (options.cache) {
+ parts.push(indent2(generateCacheFooter('stack[0]')));
+ }
+
+ parts.push([
+ '',
+ ' return stack[0];',
+ '}'
+ ].join('\n'));
+
+ 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() {
+ var n, values;
+
+ if (arguments.length === 0) {
+ return s(this.sp--);
+ } else {
+ n = arguments[0];
+ values = utils.map(utils.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;
+
+ ip += baseLength;
+ thenCode = compile(bc.slice(ip, ip + thenLength));
+ ip += thenLength;
+ if (elseLength > 0) {
+ stack.sp = baseSp;
+ elseCode = compile(bc.slice(ip, ip + elseLength));
+ ip += elseLength;
+ }
+
+ 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],
+ bodyCode;
+
+ ip += baseLength;
+ bodyCode = compile(bc.slice(ip, ip + bodyLength));
+ ip += bodyLength;
+
+ parts.push('while (' + cond + ') {');
+ parts.push(indent2(bodyCode));
+ parts.push('}');
+ }
+
+ function compileCall(cond) {
+ var baseLength = 4,
+ paramsLength = bc[ip + baseLength - 1];
+
+ var value = c(bc[ip + 1]) + '('
+ + utils.map(
+ bc.slice(ip + baseLength, ip + baseLength + paramsLength),
+ stackIndex
+ )
+ + ')';
+ stack.pop(bc[ip + 2]);
+ parts.push(stack.push(value));
+ ip += baseLength + paramsLength;
+ }
+
+ /*
+ * Extracted into a function just to silence JSHint complaining about
+ * creating functions in a loop.
+ */
+ function stackIndex(p) {
+ return stack.index(p);
+ }
+
+ while (ip < end) {
+ switch (bc[ip]) {
+ case op.PUSH: // PUSH c
+ /*
+ * Hack: One of the constants can be an empty array. It needs to be
+ * handled specially because it can be modified later on the stack
+ * by |APPEND|.
+ */
+ parts.push(
+ stack.push(ast.consts[bc[ip + 1]] === "[]" ? "[]" : 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.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.NIP_CURR_POS: // NIP_CURR_POS
+ value = stack.pop();
+ parts.push('peg$currPos = ' + 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
+ stack.pop();
+ parts.push(
+ stack.push('input.substring(' + stack.top() + ', 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() + ' === null', 0);
+ break;
+
+ case op.IF_NOT_ERROR: // IF_NOT_ERROR t, f
+ compileCondition(stack.top() + ' !== null', 0);
+ break;
+
+ case op.WHILE_NOT_ERROR: // WHILE_NOT_ERROR b
+ compileLoop(stack.top() + ' !== null', 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, '
+ + 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('null'));
+ parts.push('if (peg$silentFails === 0) { peg$fail(' + c(bc[ip + 1]) + '); }');
+ ip += 2;
+ break;
+
+ case op.REPORT_SAVED_POS: // REPORT_SAVED_POS p
+ parts.push('peg$reportedPos = ' + stack.index(bc[ip + 1]) + ';');
+ ip += 2;
+ break;
+
+ case op.REPORT_CURR_POS: // REPORT_CURR_POS
+ parts.push('peg$reportedPos = 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 + '() {',
+ ' var ' + utils.map(utils.range(0, stack.maxSp + 1), s).join(', ') + ';',
+ ''
+ ].join('\n'));
+
+ if (options.cache) {
+ parts.push(indent2(
+ generateCacheHeader(utils.indexOfRuleByName(ast, rule.name))
+ ));
+ }
+
+ parts.push(indent2(code));
+
+ if (options.cache) {
+ parts.push(indent2(generateCacheFooter('s0')));
+ }
+
+ parts.push([
+ '',
+ ' return s0;',
+ '}'
+ ].join('\n'));
+
+ return parts.join('\n');
+ }
+
+ var parts = [],
+ startRuleIndices, startRuleIndex,
+ startRuleFunctions, startRuleFunction;
+
+ parts.push([
+ '(function() {',
+ ' /*',
+ ' * Generated by PEG.js 0.7.0.',
+ ' *',
+ ' * http://pegjs.majda.cz/',
+ ' */',
+ '',
+ ' function subclass(child, parent) {',
+ ' function ctor() { this.constructor = child; }',
+ ' ctor.prototype = parent.prototype;',
+ ' child.prototype = new ctor();',
+ ' }',
+ '',
+ ' function SyntaxError(expected, found, offset, line, column) {',
+ ' function buildMessage(expected, found) {',
+ ' function stringEscape(s) {',
+ ' function hex(ch) { return ch.charCodeAt(0).toString(16).toUpperCase(); }',
+ '',
+ /*
+ * ECMA-262, 5th ed., 7.8.4: All characters may appear literally in a string
+ * literal except for the closing quote character, backslash, carriage
+ * return, line separator, paragraph separator, and line feed. Any character
+ * may appear in the form of an escape sequence.
+ *
+ * For portability, we also escape escape all control and non-ASCII
+ * characters. Note that "\0" and "\v" escape sequences are not used because
+ * JSHint does not like the first and IE the second.
+ */
+ ' return s',
+ ' .replace(/\\\\/g, \'\\\\\\\\\')', // backslash
+ ' .replace(/"/g, \'\\\\"\')', // closing double quote
+ ' .replace(/\\x08/g, \'\\\\b\')', // backspace
+ ' .replace(/\\t/g, \'\\\\t\')', // horizontal tab
+ ' .replace(/\\n/g, \'\\\\n\')', // line feed
+ ' .replace(/\\f/g, \'\\\\f\')', // form feed
+ ' .replace(/\\r/g, \'\\\\r\')', // carriage return
+ ' .replace(/[\\x00-\\x07\\x0B\\x0E\\x0F]/g, function(ch) { return \'\\\\x0\' + hex(ch); })',
+ ' .replace(/[\\x10-\\x1F\\x80-\\xFF]/g, function(ch) { return \'\\\\x\' + hex(ch); })',
+ ' .replace(/[\\u0180-\\u0FFF]/g, function(ch) { return \'\\\\u0\' + hex(ch); })',
+ ' .replace(/[\\u1080-\\uFFFF]/g, function(ch) { return \'\\\\u\' + hex(ch); });',
+ ' }',
+ '',
+ ' var expectedDesc, foundDesc;',
+ '',
+ ' switch (expected.length) {',
+ ' case 0:',
+ ' expectedDesc = "end of input";',
+ ' break;',
+ '',
+ ' case 1:',
+ ' expectedDesc = expected[0];',
+ ' break;',
+ '',
+ ' default:',
+ ' expectedDesc = expected.slice(0, -1).join(", ")',
+ ' + " or "',
+ ' + expected[expected.length - 1];',
+ ' }',
+ '',
+ ' foundDesc = found ? "\\"" + stringEscape(found) + "\\"" : "end of input";',
+ '',
+ ' return "Expected " + expectedDesc + " but " + foundDesc + " found.";',
+ ' }',
+ '',
+ ' this.expected = expected;',
+ ' this.found = found;',
+ ' this.offset = offset;',
+ ' this.line = line;',
+ ' this.column = column;',
+ '',
+ ' this.name = "SyntaxError";',
+ ' this.message = buildMessage(expected, found);',
+ ' }',
+ '',
+ ' subclass(SyntaxError, Error);',
+ '',
+ ' function parse(input) {',
+ ' var options = arguments.length > 1 ? arguments[1] : {},',
+ ''
+ ].join('\n'));
+
+ if (options.optimize === "size") {
+ startRuleIndices = '{ '
+ + utils.map(
+ options.allowedStartRules,
+ function(r) { return r + ': ' + utils.indexOfRuleByName(ast, r); }
+ ).join(', ')
+ + ' }';
+ startRuleIndex = utils.indexOfRuleByName(ast, options.allowedStartRules[0]);
+
+ parts.push([
+ ' peg$startRuleIndices = ' + startRuleIndices + ',',
+ ' peg$startRuleIndex = ' + startRuleIndex + ','
+ ].join('\n'));
+ } else {
+ startRuleFunctions = '{ '
+ + utils.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(indent8(generateTables()));
+
+ parts.push([
+ '',
+ ' peg$currPos = 0,',
+ ' peg$reportedPos = 0,',
+ ' peg$cachedPos = 0,',
+ ' peg$cachedPosDetails = { line: 1, column: 1, seenCR: false },',
+ ' peg$maxFailPos = 0,',
+ ' peg$maxFailExpected = [],',
+ ' peg$silentFails = 0,', // 0 = report failures, > 0 = silence failures
+ ''
+ ].join('\n'));
+
+ if (options.cache) {
+ parts.push(' peg$cache = {},');
+ }
+
+ 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$reportedPos, peg$currPos);',
+ ' }',
+ '',
+ ' function offset() {',
+ ' return peg$reportedPos;',
+ ' }',
+ '',
+ ' function line() {',
+ ' return peg$computePosDetails(peg$reportedPos).line;',
+ ' }',
+ '',
+ ' function column() {',
+ ' return peg$computePosDetails(peg$reportedPos).column;',
+ ' }',
+ '',
+ ' function peg$computePosDetails(pos) {',
+ ' function advance(details, pos) {',
+ ' var p, ch;',
+ '',
+ ' for (p = 0; p < pos; p++) {',
+ ' ch = input.charAt(p);',
+ ' if (ch === "\\n") {',
+ ' if (!details.seenCR) { details.line++; }',
+ ' details.column = 1;',
+ ' details.seenCR = false;',
+ ' } else if (ch === "\\r" || ch === "\\u2028" || ch === "\\u2029") {',
+ ' details.line++;',
+ ' details.column = 1;',
+ ' details.seenCR = true;',
+ ' } else {',
+ ' details.column++;',
+ ' details.seenCR = false;',
+ ' }',
+ ' }',
+ ' }',
+ '',
+ ' if (peg$cachedPos !== pos) {',
+ ' if (peg$cachedPos > pos) {',
+ ' peg$cachedPos = 0;',
+ ' peg$cachedPosDetails = { line: 1, column: 1, seenCR: false };',
+ ' }',
+ ' peg$cachedPos = pos;',
+ ' advance(peg$cachedPosDetails, peg$cachedPos);',
+ ' }',
+ '',
+ ' return peg$cachedPosDetails;',
+ ' }',
+ '',
+ ' 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$cleanupExpected(expected) {',
+ ' var i;',
+ '',
+ ' expected.sort();',
+ '',
+ ' for (i = 1; i < expected.length; i++) {',
+ ' if (expected[i - 1] === expected[i]) {',
+ ' expected.splice(i, 1);',
+ ' }',
+ ' }',
+ ' }',
+ ''
+ ].join('\n'));
+
+ if (options.optimize === "size") {
+ parts.push(indent4(generateInterpreter()));
+ parts.push('');
+ } else {
+ utils.each(ast.rules, function(rule) {
+ parts.push(indent4(generateRuleFunction(rule)));
+ parts.push('');
+ });
+ }
+
+ if (ast.initializer) {
+ parts.push(indent4(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 !== null && peg$currPos === input.length) {',
+ ' return peg$result;',
+ ' } else {',
+ ' peg$cleanupExpected(peg$maxFailExpected);',
+ ' peg$reportedPos = Math.max(peg$currPos, peg$maxFailPos);',
+ '',
+ ' throw new SyntaxError(',
+ ' peg$maxFailExpected,',
+ ' peg$reportedPos < input.length ? input.charAt(peg$reportedPos) : null,',
+ ' peg$reportedPos,',
+ ' peg$computePosDetails(peg$reportedPos).line,',
+ ' peg$computePosDetails(peg$reportedPos).column',
+ ' );',
+ ' }',
+ ' }',
+ '',
+ ' return {',
+ ' SyntaxError: SyntaxError,',
+ ' parse : parse',
+ ' };',
+ '})()'
+ ].join('\n'));
+
+ ast.code = parts.join('\n');
+};
diff --git a/lib/parser.js b/lib/parser.js
index 26a0dce..8427ad3 100644
--- a/lib/parser.js
+++ b/lib/parser.js
@@ -1,282 +1,93 @@
-module.exports = (function(){
+module.exports = (function() {
/*
* Generated by PEG.js 0.7.0.
*
* http://pegjs.majda.cz/
*/
-
+
function subclass(child, parent) {
function ctor() { this.constructor = child; }
ctor.prototype = parent.prototype;
child.prototype = new ctor();
}
-
- 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 SyntaxError(expected, found, offset, line, column) {
+ function buildMessage(expected, found) {
+ function stringEscape(s) {
+ function hex(ch) { return ch.charCodeAt(0).toString(16).toUpperCase(); }
+
+ return s
+ .replace(/\\/g, '\\\\')
+ .replace(/"/g, '\\"')
+ .replace(/\x08/g, '\\b')
+ .replace(/\t/g, '\\t')
+ .replace(/\n/g, '\\n')
+ .replace(/\f/g, '\\f')
+ .replace(/\r/g, '\\r')
+ .replace(/[\x00-\x07\x0B\x0E\x0F]/g, function(ch) { return '\\x0' + hex(ch); })
+ .replace(/[\x10-\x1F\x80-\xFF]/g, function(ch) { return '\\x' + hex(ch); })
+ .replace(/[\u0180-\u0FFF]/g, function(ch) { return '\\u0' + hex(ch); })
+ .replace(/[\u1080-\uFFFF]/g, function(ch) { return '\\u' + hex(ch); });
+ }
+
+ var expectedDesc, foundDesc;
+
+ switch (expected.length) {
+ case 0:
+ expectedDesc = "end of input";
+ break;
+
+ case 1:
+ expectedDesc = expected[0];
+ break;
+
+ default:
+ expectedDesc = expected.slice(0, -1).join(", ")
+ + " or "
+ + expected[expected.length - 1];
+ }
+
+ foundDesc = found ? "\"" + stringEscape(found) + "\"" : "end of input";
+
+ return "Expected " + expectedDesc + " but " + foundDesc + " found.";
+ }
+
+ this.expected = expected;
+ this.found = found;
+ this.offset = offset;
+ this.line = line;
+ this.column = column;
+
+ this.name = "SyntaxError";
+ this.message = buildMessage(expected, found);
}
-
- var result = {
- /*
- * Parses the input with a generated parser. If the parsing is successful,
- * returns a value explicitly or implicitly specified by the grammar from
- * which the parser was generated (see |PEG.buildParser|). If the parsing is
- * unsuccessful, throws |PEG.parser.SyntaxError| describing the error.
- */
- parse: function(input) {
- var parseFunctions = {
- "grammar": parse_grammar
- };
-
- var options = arguments.length > 1 ? arguments[1] : {},
- startRule;
-
- if (options.startRule !== undefined) {
- startRule = options.startRule;
-
- if (parseFunctions[startRule] === undefined) {
- throw new Error("Can't start parsing from rule " + quote(startRule) + ".");
- }
- } else {
- startRule = "grammar";
- }
-
- var pos = 0;
- var reportedPos = 0;
- var cachedReportedPos = 0;
- var cachedReportedPosDetails = { line: 1, column: 1, seenCR: false };
- var reportFailures = 0;
- var rightmostFailuresPos = 0;
- var rightmostFailuresExpected = [];
-
- function padLeft(input, padding, length) {
- var result = input;
-
- var padLength = length - input.length;
- for (var i = 0; i < padLength; i++) {
- result = padding + result;
- }
-
- return result;
- }
-
- function escape(ch) {
- var charCode = ch.charCodeAt(0);
- var escapeChar;
- var length;
-
- if (charCode <= 0xFF) {
- escapeChar = 'x';
- length = 2;
- } else {
- escapeChar = 'u';
- length = 4;
- }
-
- return '\\' + escapeChar + padLeft(charCode.toString(16).toUpperCase(), '0', length);
- }
-
- function computeReportedPosDetails() {
- function advanceCachedReportedPos() {
- var ch;
-
- for (; cachedReportedPos < reportedPos; cachedReportedPos++) {
- ch = input.charAt(cachedReportedPos);
- if (ch === "\n") {
- if (!cachedReportedPosDetails.seenCR) { cachedReportedPosDetails.line++; }
- cachedReportedPosDetails.column = 1;
- cachedReportedPosDetails.seenCR = false;
- } else if (ch === "\r" || ch === "\u2028" || ch === "\u2029") {
- cachedReportedPosDetails.line++;
- cachedReportedPosDetails.column = 1;
- cachedReportedPosDetails.seenCR = true;
- } else {
- cachedReportedPosDetails.column++;
- cachedReportedPosDetails.seenCR = false;
- }
- }
- }
-
- if (cachedReportedPos !== reportedPos) {
- if (cachedReportedPos > reportedPos) {
- cachedReportedPos = 0;
- cachedReportedPosDetails = { line: 1, column: 1, seenCR: false };
- }
- advanceCachedReportedPos();
- }
-
- return cachedReportedPosDetails;
- }
-
- function offset() {
- return reportedPos;
- }
-
- function line() {
- return computeReportedPosDetails().line;
- }
-
- function column() {
- return computeReportedPosDetails().column;
- }
-
- function matchFailed(failure) {
- if (pos < rightmostFailuresPos) {
- return;
- }
-
- if (pos > rightmostFailuresPos) {
- rightmostFailuresPos = pos;
- rightmostFailuresExpected = [];
- }
-
- rightmostFailuresExpected.push(failure);
- }
-
- function parse_grammar() {
- var r0, r1, r2, r3, r4, r5, r6;
-
- r1 = pos;
- r2 = pos;
- r3 = parse___();
- if (r3 !== null) {
- r4 = parse_initializer();
- r4 = r4 !== null ? r4 : "";
- if (r4 !== null) {
- r6 = parse_rule();
- if (r6 !== null) {
- r5 = [];
- while (r6 !== null) {
- r5.push(r6);
- r6 = parse_rule();
- }
- } else {
- r5 = null;
- }
- if (r5 !== null) {
- r0 = [r3, r4, r5];
- } else {
- r0 = null;
- pos = r2;
- }
- } else {
- r0 = null;
- pos = r2;
- }
- } else {
- r0 = null;
- pos = r2;
- }
- if (r0 !== null) {
- reportedPos = r1;
- r0 = (function(initializer, rules) {
+
+ subclass(SyntaxError, Error);
+
+ function parse(input) {
+ var options = arguments.length > 1 ? arguments[1] : {},
+
+ peg$startRuleFunctions = { grammar: peg$parsegrammar },
+ peg$startRuleFunction = peg$parsegrammar,
+
+ peg$c0 = null,
+ peg$c1 = "",
+ peg$c2 = [],
+ peg$c3 = function(initializer, rules) {
return {
type: "grammar",
initializer: initializer !== "" ? initializer : null,
rules: rules,
startRule: rules[0].name
};
- })(r4, r5);
- }
- if (r0 === null) {
- pos = r1;
- }
- return r0;
- }
-
- function parse_initializer() {
- var r0, r1, r2, r3, r4;
-
- r1 = pos;
- r2 = pos;
- r3 = parse_action();
- if (r3 !== null) {
- r4 = parse_semicolon();
- r4 = r4 !== null ? r4 : "";
- if (r4 !== null) {
- r0 = [r3, r4];
- } else {
- r0 = null;
- pos = r2;
- }
- } else {
- r0 = null;
- pos = r2;
- }
- if (r0 !== null) {
- reportedPos = r1;
- r0 = (function(code) {
+ },
+ peg$c4 = function(code) {
return {
type: "initializer",
code: code
};
- })(r3);
- }
- if (r0 === null) {
- pos = r1;
- }
- return r0;
- }
-
- function parse_rule() {
- var r0, r1, r2, r3, r4, r5, r6, r7;
-
- r1 = pos;
- r2 = pos;
- r3 = parse_identifier();
- if (r3 !== null) {
- r4 = parse_string();
- r4 = r4 !== null ? r4 : "";
- if (r4 !== null) {
- r5 = parse_equals();
- if (r5 !== null) {
- r6 = parse_choice();
- if (r6 !== null) {
- r7 = parse_semicolon();
- r7 = r7 !== null ? r7 : "";
- if (r7 !== null) {
- r0 = [r3, r4, r5, r6, r7];
- } else {
- r0 = null;
- pos = r2;
- }
- } else {
- r0 = null;
- pos = r2;
- }
- } else {
- r0 = null;
- pos = r2;
- }
- } else {
- r0 = null;
- pos = r2;
- }
- } else {
- r0 = null;
- pos = r2;
- }
- if (r0 !== null) {
- reportedPos = r1;
- r0 = (function(name, displayName, expression) {
+ },
+ peg$c5 = function(name, displayName, expression) {
return {
type: "rule",
name: name,
@@ -288,66 +99,8 @@ module.exports = (function(){
}
: expression
};
- })(r3, r4, r6);
- }
- if (r0 === null) {
- pos = r1;
- }
- return r0;
- }
-
- function parse_choice() {
- var r0, r1, r2, r3, r4, r5, r6, r7, r8;
-
- r1 = pos;
- r2 = pos;
- r3 = parse_sequence();
- if (r3 !== null) {
- r4 = [];
- r6 = pos;
- r7 = parse_slash();
- if (r7 !== null) {
- r8 = parse_sequence();
- if (r8 !== null) {
- r5 = [r7, r8];
- } else {
- r5 = null;
- pos = r6;
- }
- } else {
- r5 = null;
- pos = r6;
- }
- while (r5 !== null) {
- r4.push(r5);
- r6 = pos;
- r7 = parse_slash();
- if (r7 !== null) {
- r8 = parse_sequence();
- if (r8 !== null) {
- r5 = [r7, r8];
- } else {
- r5 = null;
- pos = r6;
- }
- } else {
- r5 = null;
- pos = r6;
- }
- }
- if (r4 !== null) {
- r0 = [r3, r4];
- } else {
- r0 = null;
- pos = r2;
- }
- } else {
- r0 = null;
- pos = r2;
- }
- if (r0 !== null) {
- reportedPos = r1;
- r0 = (function(head, tail) {
+ },
+ peg$c6 = function(head, tail) {
if (tail.length > 0) {
var alternatives = [head].concat(utils.map(
tail,
@@ -360,40 +113,8 @@ module.exports = (function(){
} else {
return head;
}
- })(r3, r4);
- }
- if (r0 === null) {
- pos = r1;
- }
- return r0;
- }
-
- function parse_sequence() {
- var r0, r1, r2, r3, r4;
-
- r1 = pos;
- r2 = pos;
- r3 = [];
- r4 = parse_labeled();
- while (r4 !== null) {
- r3.push(r4);
- r4 = parse_labeled();
- }
- if (r3 !== null) {
- r4 = parse_action();
- if (r4 !== null) {
- r0 = [r3, r4];
- } else {
- r0 = null;
- pos = r2;
- }
- } else {
- r0 = null;
- pos = r2;
- }
- if (r0 !== null) {
- reportedPos = r1;
- r0 = (function(elements, code) {
+ },
+ peg$c7 = function(elements, code) {
var expression = elements.length !== 1
? {
type: "sequence",
@@ -405,2591 +126,2879 @@ module.exports = (function(){
expression: expression,
code: code
};
- })(r3, r4);
- }
- if (r0 === null) {
- pos = r1;
- }
- if (r0 === null) {
- r1 = pos;
- r0 = [];
- r2 = parse_labeled();
- while (r2 !== null) {
- r0.push(r2);
- r2 = parse_labeled();
- }
- if (r0 !== null) {
- reportedPos = r1;
- r0 = (function(elements) {
- return elements.length !== 1
- ? {
- type: "sequence",
- elements: elements
- }
- : elements[0];
- })(r0);
- }
- if (r0 === null) {
- pos = r1;
- }
- }
- return r0;
- }
-
- function parse_labeled() {
- var r0, r1, r2, r3, r4, r5;
-
- r1 = pos;
- r2 = pos;
- r3 = parse_identifier();
- if (r3 !== null) {
- r4 = parse_colon();
- if (r4 !== null) {
- r5 = parse_prefixed();
- if (r5 !== null) {
- r0 = [r3, r4, r5];
+ },
+ peg$c8 = function(elements) {
+ return elements.length !== 1
+ ? {
+ type: "sequence",
+ elements: elements
+ }
+ : elements[0];
+ },
+ peg$c9 = function(label, expression) {
+ return {
+ type: "labeled",
+ label: label,
+ expression: expression
+ };
+ },
+ peg$c10 = function(expression) {
+ return {
+ type: "text",
+ expression: expression
+ };
+ },
+ peg$c11 = function(code) {
+ return {
+ type: "semantic_and",
+ code: code
+ };
+ },
+ peg$c12 = function(expression) {
+ return {
+ type: "simple_and",
+ expression: expression
+ };
+ },
+ peg$c13 = function(code) {
+ return {
+ type: "semantic_not",
+ code: code
+ };
+ },
+ peg$c14 = function(expression) {
+ return {
+ type: "simple_not",
+ expression: expression
+ };
+ },
+ peg$c15 = function(expression) {
+ return {
+ type: "optional",
+ expression: expression
+ };
+ },
+ peg$c16 = function(expression) {
+ return {
+ type: "zero_or_more",
+ expression: expression
+ };
+ },
+ peg$c17 = function(expression) {
+ return {
+ type: "one_or_more",
+ expression: expression
+ };
+ },
+ peg$c18 = function(name) {
+ return {
+ type: "rule_ref",
+ name: name
+ };
+ },
+ peg$c19 = function() { return { type: "any" }; },
+ peg$c20 = function(expression) { return expression; },
+ peg$c21 = "action",
+ peg$c22 = function(braced) { return braced.substr(1, braced.length - 2); },
+ peg$c23 = "{",
+ peg$c24 = "\"{\"",
+ peg$c25 = "}",
+ peg$c26 = "\"}\"",
+ peg$c27 = /^[^{}]/,
+ peg$c28 = "[^{}]",
+ peg$c29 = "=",
+ peg$c30 = "\"=\"",
+ peg$c31 = function() { return "="; },
+ peg$c32 = ":",
+ peg$c33 = "\":\"",
+ peg$c34 = function() { return ":"; },
+ peg$c35 = ";",
+ peg$c36 = "\";\"",
+ peg$c37 = function() { return ";"; },
+ peg$c38 = "/",
+ peg$c39 = "\"/\"",
+ peg$c40 = function() { return "/"; },
+ peg$c41 = "&",
+ peg$c42 = "\"&\"",
+ peg$c43 = function() { return "&"; },
+ peg$c44 = "!",
+ peg$c45 = "\"!\"",
+ peg$c46 = function() { return "!"; },
+ peg$c47 = "$",
+ peg$c48 = "\"$\"",
+ peg$c49 = function() { return "$"; },
+ peg$c50 = "?",
+ peg$c51 = "\"?\"",
+ peg$c52 = function() { return "?"; },
+ peg$c53 = "*",
+ peg$c54 = "\"*\"",
+ peg$c55 = function() { return "*"; },
+ peg$c56 = "+",
+ peg$c57 = "\"+\"",
+ peg$c58 = function() { return "+"; },
+ peg$c59 = "(",
+ peg$c60 = "\"(\"",
+ peg$c61 = function() { return "("; },
+ peg$c62 = ")",
+ peg$c63 = "\")\"",
+ peg$c64 = function() { return ")"; },
+ peg$c65 = ".",
+ peg$c66 = "\".\"",
+ peg$c67 = function() { return "."; },
+ peg$c68 = "identifier",
+ peg$c69 = "_",
+ peg$c70 = "\"_\"",
+ peg$c71 = function(chars) { return chars; },
+ peg$c72 = "literal",
+ peg$c73 = "i",
+ peg$c74 = "\"i\"",
+ peg$c75 = function(value, flags) {
+ return {
+ type: "literal",
+ value: value,
+ ignoreCase: flags === "i"
+ };
+ },
+ peg$c76 = "string",
+ peg$c77 = function(string) { return string; },
+ peg$c78 = "\"",
+ peg$c79 = "\"\\\"\"",
+ peg$c80 = function(chars) { return chars.join(""); },
+ peg$c81 = "\\",
+ peg$c82 = "\"\\\\\"",
+ peg$c83 = "any character",
+ peg$c84 = function(char_) { return char_; },
+ peg$c85 = "'",
+ peg$c86 = "\"'\"",
+ peg$c87 = "character class",
+ peg$c88 = "[",
+ peg$c89 = "\"[\"",
+ peg$c90 = "^",
+ peg$c91 = "\"^\"",
+ peg$c92 = "]",
+ peg$c93 = "\"]\"",
+ peg$c94 = function(inverted, parts, flags) {
+ var partsConverted = utils.map(parts, function(part) { return part.data; });
+ var rawText = "["
+ + inverted
+ + utils.map(parts, function(part) { return part.rawText; }).join("")
+ + "]"
+ + flags;
+
+ return {
+ type: "class",
+ parts: partsConverted,
+ // FIXME: Get the raw text from the input directly.
+ rawText: rawText,
+ inverted: inverted === "^",
+ ignoreCase: flags === "i"
+ };
+ },
+ peg$c95 = "-",
+ peg$c96 = "\"-\"",
+ peg$c97 = function(begin, end) {
+ if (begin.data.charCodeAt(0) > end.data.charCodeAt(0)) {
+ throw new this.SyntaxError(
+ "Invalid character range: " + begin.rawText + "-" + end.rawText + "."
+ );
+ }
+
+ return {
+ data: [begin.data, end.data],
+ // FIXME: Get the raw text from the input directly.
+ rawText: begin.rawText + "-" + end.rawText
+ };
+ },
+ peg$c98 = function(char_) {
+ return {
+ data: char_,
+ // FIXME: Get the raw text from the input directly.
+ rawText: utils.quoteForRegexpClass(char_)
+ };
+ },
+ peg$c99 = "x",
+ peg$c100 = "\"x\"",
+ peg$c101 = "u",
+ peg$c102 = "\"u\"",
+ peg$c103 = function(char_) {
+ return char_
+ .replace("b", "\b")
+ .replace("f", "\f")
+ .replace("n", "\n")
+ .replace("r", "\r")
+ .replace("t", "\t")
+ .replace("v", "\x0B"); // IE does not recognize "\v".
+ },
+ peg$c104 = "\\0",
+ peg$c105 = "\"\\\\0\"",
+ peg$c106 = function() { return "\x00"; },
+ peg$c107 = "\\x",
+ peg$c108 = "\"\\\\x\"",
+ peg$c109 = function(digits) {
+ return String.fromCharCode(parseInt(digits, 16));
+ },
+ peg$c110 = "\\u",
+ peg$c111 = "\"\\\\u\"",
+ peg$c112 = function(eol) { return eol; },
+ peg$c113 = /^[0-9]/,
+ peg$c114 = "[0-9]",
+ peg$c115 = /^[0-9a-fA-F]/,
+ peg$c116 = "[0-9a-fA-F]",
+ peg$c117 = /^[a-z]/,
+ peg$c118 = "[a-z]",
+ peg$c119 = /^[A-Z]/,
+ peg$c120 = "[A-Z]",
+ peg$c121 = "comment",
+ peg$c122 = "//",
+ peg$c123 = "\"//\"",
+ peg$c124 = "/*",
+ peg$c125 = "\"/*\"",
+ peg$c126 = "*/",
+ peg$c127 = "\"*/\"",
+ peg$c128 = "end of line",
+ peg$c129 = "\n",
+ peg$c130 = "\"\\n\"",
+ peg$c131 = "\r\n",
+ peg$c132 = "\"\\r\\n\"",
+ peg$c133 = "\r",
+ peg$c134 = "\"\\r\"",
+ peg$c135 = "\u2028",
+ peg$c136 = "\"\\u2028\"",
+ peg$c137 = "\u2029",
+ peg$c138 = "\"\\u2029\"",
+ peg$c139 = /^[\n\r\u2028\u2029]/,
+ peg$c140 = "[\\n\\r\\u2028\\u2029]",
+ peg$c141 = "whitespace",
+ peg$c142 = /^[ \t\x0B\f\xA0\uFEFF\u1680\u180E\u2000-\u200A\u202F\u205F\u3000]/,
+ peg$c143 = "[ \\t\\x0B\\f\\xA0\\uFEFF\\u1680\\u180E\\u2000-\\u200A\\u202F\\u205F\\u3000]",
+
+ peg$currPos = 0,
+ peg$reportedPos = 0,
+ peg$cachedPos = 0,
+ peg$cachedPosDetails = { line: 1, column: 1, seenCR: false },
+ peg$maxFailPos = 0,
+ peg$maxFailExpected = [],
+ peg$silentFails = 0,
+
+ peg$result;
+
+ 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];
+ }
+
+ function text() {
+ return input.substring(peg$reportedPos, peg$currPos);
+ }
+
+ function offset() {
+ return peg$reportedPos;
+ }
+
+ function line() {
+ return peg$computePosDetails(peg$reportedPos).line;
+ }
+
+ function column() {
+ return peg$computePosDetails(peg$reportedPos).column;
+ }
+
+ function peg$computePosDetails(pos) {
+ function advance(details, pos) {
+ var p, ch;
+
+ for (p = 0; p < pos; p++) {
+ ch = input.charAt(p);
+ if (ch === "\n") {
+ if (!details.seenCR) { details.line++; }
+ details.column = 1;
+ details.seenCR = false;
+ } else if (ch === "\r" || ch === "\u2028" || ch === "\u2029") {
+ details.line++;
+ details.column = 1;
+ details.seenCR = true;
+ } else {
+ details.column++;
+ details.seenCR = false;
+ }
+ }
+ }
+
+ if (peg$cachedPos !== pos) {
+ if (peg$cachedPos > pos) {
+ peg$cachedPos = 0;
+ peg$cachedPosDetails = { line: 1, column: 1, seenCR: false };
+ }
+ peg$cachedPos = pos;
+ advance(peg$cachedPosDetails, peg$cachedPos);
+ }
+
+ return peg$cachedPosDetails;
+ }
+
+ 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$cleanupExpected(expected) {
+ var i;
+
+ expected.sort();
+
+ for (i = 1; i < expected.length; i++) {
+ if (expected[i - 1] === expected[i]) {
+ expected.splice(i, 1);
+ }
+ }
+ }
+
+ function peg$parsegrammar() {
+ var s0, s1, s2, s3, s4;
+
+ s0 = peg$currPos;
+ s1 = peg$parse__();
+ if (s1 !== null) {
+ s2 = peg$parseinitializer();
+ if (s2 === null) {
+ s2 = peg$c1;
+ }
+ if (s2 !== null) {
+ s3 = [];
+ s4 = peg$parserule();
+ if (s4 !== null) {
+ while (s4 !== null) {
+ s3.push(s4);
+ s4 = peg$parserule();
+ }
+ } else {
+ s3 = peg$c0;
+ }
+ if (s3 !== null) {
+ peg$reportedPos = s0;
+ s1 = peg$c3(s2,s3);
+ if (s1 === null) {
+ peg$currPos = s0;
+ s0 = s1;
} else {
- r0 = null;
- pos = r2;
+ s0 = s1;
}
} else {
- r0 = null;
- pos = r2;
+ peg$currPos = s0;
+ s0 = peg$c0;
}
} else {
- r0 = null;
- pos = r2;
+ peg$currPos = s0;
+ s0 = peg$c0;
}
- if (r0 !== null) {
- reportedPos = r1;
- r0 = (function(label, expression) {
- return {
- type: "labeled",
- label: label,
- expression: expression
- };
- })(r3, r5);
+ } else {
+ peg$currPos = s0;
+ s0 = peg$c0;
+ }
+
+ return s0;
+ }
+
+ function peg$parseinitializer() {
+ var s0, s1, s2;
+
+ s0 = peg$currPos;
+ s1 = peg$parseaction();
+ if (s1 !== null) {
+ s2 = peg$parsesemicolon();
+ if (s2 === null) {
+ s2 = peg$c1;
+ }
+ if (s2 !== null) {
+ peg$reportedPos = s0;
+ s1 = peg$c4(s1);
+ if (s1 === null) {
+ peg$currPos = s0;
+ s0 = s1;
+ } else {
+ s0 = s1;
+ }
+ } else {
+ peg$currPos = s0;
+ s0 = peg$c0;
+ }
+ } else {
+ peg$currPos = s0;
+ s0 = peg$c0;
+ }
+
+ return s0;
+ }
+
+ function peg$parserule() {
+ var s0, s1, s2, s3, s4, s5;
+
+ s0 = peg$currPos;
+ s1 = peg$parseidentifier();
+ if (s1 !== null) {
+ s2 = peg$parsestring();
+ if (s2 === null) {
+ s2 = peg$c1;
+ }
+ if (s2 !== null) {
+ s3 = peg$parseequals();
+ if (s3 !== null) {
+ s4 = peg$parsechoice();
+ if (s4 !== null) {
+ s5 = peg$parsesemicolon();
+ if (s5 === null) {
+ s5 = peg$c1;
+ }
+ if (s5 !== null) {
+ peg$reportedPos = s0;
+ s1 = peg$c5(s1,s2,s4);
+ if (s1 === null) {
+ peg$currPos = s0;
+ s0 = s1;
+ } else {
+ s0 = s1;
+ }
+ } else {
+ peg$currPos = s0;
+ s0 = peg$c0;
+ }
+ } else {
+ peg$currPos = s0;
+ s0 = peg$c0;
+ }
+ } else {
+ peg$currPos = s0;
+ s0 = peg$c0;
+ }
+ } else {
+ peg$currPos = s0;
+ s0 = peg$c0;
+ }
+ } else {
+ peg$currPos = s0;
+ s0 = peg$c0;
+ }
+
+ return s0;
+ }
+
+ function peg$parsechoice() {
+ var s0, s1, s2, s3, s4, s5;
+
+ s0 = peg$currPos;
+ s1 = peg$parsesequence();
+ if (s1 !== null) {
+ s2 = [];
+ s3 = peg$currPos;
+ s4 = peg$parseslash();
+ if (s4 !== null) {
+ s5 = peg$parsesequence();
+ if (s5 !== null) {
+ s4 = [s4, s5];
+ s3 = s4;
+ } else {
+ peg$currPos = s3;
+ s3 = peg$c0;
+ }
+ } else {
+ peg$currPos = s3;
+ s3 = peg$c0;
+ }
+ while (s3 !== null) {
+ s2.push(s3);
+ s3 = peg$currPos;
+ s4 = peg$parseslash();
+ if (s4 !== null) {
+ s5 = peg$parsesequence();
+ if (s5 !== null) {
+ s4 = [s4, s5];
+ s3 = s4;
+ } else {
+ peg$currPos = s3;
+ s3 = peg$c0;
+ }
+ } else {
+ peg$currPos = s3;
+ s3 = peg$c0;
+ }
+ }
+ if (s2 !== null) {
+ peg$reportedPos = s0;
+ s1 = peg$c6(s1,s2);
+ if (s1 === null) {
+ peg$currPos = s0;
+ s0 = s1;
+ } else {
+ s0 = s1;
+ }
+ } else {
+ peg$currPos = s0;
+ s0 = peg$c0;
+ }
+ } else {
+ peg$currPos = s0;
+ s0 = peg$c0;
+ }
+
+ return s0;
+ }
+
+ function peg$parsesequence() {
+ var s0, s1, s2;
+
+ s0 = peg$currPos;
+ s1 = [];
+ s2 = peg$parselabeled();
+ while (s2 !== null) {
+ s1.push(s2);
+ s2 = peg$parselabeled();
+ }
+ if (s1 !== null) {
+ s2 = peg$parseaction();
+ if (s2 !== null) {
+ peg$reportedPos = s0;
+ s1 = peg$c7(s1,s2);
+ if (s1 === null) {
+ peg$currPos = s0;
+ s0 = s1;
+ } else {
+ s0 = s1;
+ }
+ } else {
+ peg$currPos = s0;
+ s0 = peg$c0;
+ }
+ } else {
+ peg$currPos = s0;
+ s0 = peg$c0;
+ }
+ if (s0 === null) {
+ s0 = peg$currPos;
+ s1 = [];
+ s2 = peg$parselabeled();
+ while (s2 !== null) {
+ s1.push(s2);
+ s2 = peg$parselabeled();
}
- if (r0 === null) {
- pos = r1;
+ if (s1 !== null) {
+ peg$reportedPos = s0;
+ s1 = peg$c8(s1);
}
- if (r0 === null) {
- r0 = parse_prefixed();
+ if (s1 === null) {
+ peg$currPos = s0;
+ s0 = s1;
+ } else {
+ s0 = s1;
}
- return r0;
}
-
- function parse_prefixed() {
- var r0, r1, r2, r3, r4;
-
- r1 = pos;
- r2 = pos;
- r3 = parse_dollar();
- if (r3 !== null) {
- r4 = parse_suffixed();
- if (r4 !== null) {
- r0 = [r3, r4];
+
+ return s0;
+ }
+
+ function peg$parselabeled() {
+ var s0, s1, s2, s3;
+
+ s0 = peg$currPos;
+ s1 = peg$parseidentifier();
+ if (s1 !== null) {
+ s2 = peg$parsecolon();
+ if (s2 !== null) {
+ s3 = peg$parseprefixed();
+ if (s3 !== null) {
+ peg$reportedPos = s0;
+ s1 = peg$c9(s1,s3);
+ if (s1 === null) {
+ peg$currPos = s0;
+ s0 = s1;
+ } else {
+ s0 = s1;
+ }
} else {
- r0 = null;
- pos = r2;
+ peg$currPos = s0;
+ s0 = peg$c0;
}
} else {
- r0 = null;
- pos = r2;
+ peg$currPos = s0;
+ s0 = peg$c0;
}
- if (r0 !== null) {
- reportedPos = r1;
- r0 = (function(expression) {
- return {
- type: "text",
- expression: expression
- };
- })(r4);
- }
- if (r0 === null) {
- pos = r1;
- }
- if (r0 === null) {
- r1 = pos;
- r2 = pos;
- r3 = parse_and();
- if (r3 !== null) {
- r4 = parse_action();
- if (r4 !== null) {
- r0 = [r3, r4];
+ } else {
+ peg$currPos = s0;
+ s0 = peg$c0;
+ }
+ if (s0 === null) {
+ s0 = peg$parseprefixed();
+ }
+
+ return s0;
+ }
+
+ function peg$parseprefixed() {
+ var s0, s1, s2;
+
+ s0 = peg$currPos;
+ s1 = peg$parsedollar();
+ if (s1 !== null) {
+ s2 = peg$parsesuffixed();
+ if (s2 !== null) {
+ peg$reportedPos = s0;
+ s1 = peg$c10(s2);
+ if (s1 === null) {
+ peg$currPos = s0;
+ s0 = s1;
+ } else {
+ s0 = s1;
+ }
+ } else {
+ peg$currPos = s0;
+ s0 = peg$c0;
+ }
+ } else {
+ peg$currPos = s0;
+ s0 = peg$c0;
+ }
+ if (s0 === null) {
+ s0 = peg$currPos;
+ s1 = peg$parseand();
+ if (s1 !== null) {
+ s2 = peg$parseaction();
+ if (s2 !== null) {
+ peg$reportedPos = s0;
+ s1 = peg$c11(s2);
+ if (s1 === null) {
+ peg$currPos = s0;
+ s0 = s1;
} else {
- r0 = null;
- pos = r2;
+ s0 = s1;
}
} else {
- r0 = null;
- pos = r2;
+ peg$currPos = s0;
+ s0 = peg$c0;
}
- if (r0 !== null) {
- reportedPos = r1;
- r0 = (function(code) {
- return {
- type: "semantic_and",
- code: code
- };
- })(r4);
- }
- if (r0 === null) {
- pos = r1;
- }
- if (r0 === null) {
- r1 = pos;
- r2 = pos;
- r3 = parse_and();
- if (r3 !== null) {
- r4 = parse_suffixed();
- if (r4 !== null) {
- r0 = [r3, r4];
+ } else {
+ peg$currPos = s0;
+ s0 = peg$c0;
+ }
+ if (s0 === null) {
+ s0 = peg$currPos;
+ s1 = peg$parseand();
+ if (s1 !== null) {
+ s2 = peg$parsesuffixed();
+ if (s2 !== null) {
+ peg$reportedPos = s0;
+ s1 = peg$c12(s2);
+ if (s1 === null) {
+ peg$currPos = s0;
+ s0 = s1;
} else {
- r0 = null;
- pos = r2;
+ s0 = s1;
}
} else {
- r0 = null;
- pos = r2;
- }
- if (r0 !== null) {
- reportedPos = r1;
- r0 = (function(expression) {
- return {
- type: "simple_and",
- expression: expression
- };
- })(r4);
- }
- if (r0 === null) {
- pos = r1;
- }
- if (r0 === null) {
- r1 = pos;
- r2 = pos;
- r3 = parse_not();
- if (r3 !== null) {
- r4 = parse_action();
- if (r4 !== null) {
- r0 = [r3, r4];
+ peg$currPos = s0;
+ s0 = peg$c0;
+ }
+ } else {
+ peg$currPos = s0;
+ s0 = peg$c0;
+ }
+ if (s0 === null) {
+ s0 = peg$currPos;
+ s1 = peg$parsenot();
+ if (s1 !== null) {
+ s2 = peg$parseaction();
+ if (s2 !== null) {
+ peg$reportedPos = s0;
+ s1 = peg$c13(s2);
+ if (s1 === null) {
+ peg$currPos = s0;
+ s0 = s1;
} else {
- r0 = null;
- pos = r2;
+ s0 = s1;
}
} else {
- r0 = null;
- pos = r2;
- }
- if (r0 !== null) {
- reportedPos = r1;
- r0 = (function(code) {
- return {
- type: "semantic_not",
- code: code
- };
- })(r4);
+ peg$currPos = s0;
+ s0 = peg$c0;
}
- if (r0 === null) {
- pos = r1;
- }
- if (r0 === null) {
- r1 = pos;
- r2 = pos;
- r3 = parse_not();
- if (r3 !== null) {
- r4 = parse_suffixed();
- if (r4 !== null) {
- r0 = [r3, r4];
+ } else {
+ peg$currPos = s0;
+ s0 = peg$c0;
+ }
+ if (s0 === null) {
+ s0 = peg$currPos;
+ s1 = peg$parsenot();
+ if (s1 !== null) {
+ s2 = peg$parsesuffixed();
+ if (s2 !== null) {
+ peg$reportedPos = s0;
+ s1 = peg$c14(s2);
+ if (s1 === null) {
+ peg$currPos = s0;
+ s0 = s1;
} else {
- r0 = null;
- pos = r2;
+ s0 = s1;
}
} else {
- r0 = null;
- pos = r2;
- }
- if (r0 !== null) {
- reportedPos = r1;
- r0 = (function(expression) {
- return {
- type: "simple_not",
- expression: expression
- };
- })(r4);
- }
- if (r0 === null) {
- pos = r1;
- }
- if (r0 === null) {
- r0 = parse_suffixed();
+ peg$currPos = s0;
+ s0 = peg$c0;
}
+ } else {
+ peg$currPos = s0;
+ s0 = peg$c0;
+ }
+ if (s0 === null) {
+ s0 = peg$parsesuffixed();
}
}
}
}
- return r0;
}
-
- function parse_suffixed() {
- var r0, r1, r2, r3, r4;
-
- r1 = pos;
- r2 = pos;
- r3 = parse_primary();
- if (r3 !== null) {
- r4 = parse_question();
- if (r4 !== null) {
- r0 = [r3, r4];
- } else {
- r0 = null;
- pos = r2;
- }
- } else {
- r0 = null;
- pos = r2;
+
+ return s0;
+ }
+
+ function peg$parsesuffixed() {
+ var s0, s1, s2;
+
+ s0 = peg$currPos;
+ s1 = peg$parseprimary();
+ if (s1 !== null) {
+ s2 = peg$parsequestion();
+ if (s2 !== null) {
+ peg$reportedPos = s0;
+ s1 = peg$c15(s1);
+ if (s1 === null) {
+ peg$currPos = s0;
+ s0 = s1;
+ } else {
+ s0 = s1;
+ }
+ } else {
+ peg$currPos = s0;
+ s0 = peg$c0;
}
- if (r0 !== null) {
- reportedPos = r1;
- r0 = (function(expression) {
- return {
- type: "optional",
- expression: expression
- };
- })(r3);
- }
- if (r0 === null) {
- pos = r1;
- }
- if (r0 === null) {
- r1 = pos;
- r2 = pos;
- r3 = parse_primary();
- if (r3 !== null) {
- r4 = parse_star();
- if (r4 !== null) {
- r0 = [r3, r4];
+ } else {
+ peg$currPos = s0;
+ s0 = peg$c0;
+ }
+ if (s0 === null) {
+ s0 = peg$currPos;
+ s1 = peg$parseprimary();
+ if (s1 !== null) {
+ s2 = peg$parsestar();
+ if (s2 !== null) {
+ peg$reportedPos = s0;
+ s1 = peg$c16(s1);
+ if (s1 === null) {
+ peg$currPos = s0;
+ s0 = s1;
} else {
- r0 = null;
- pos = r2;
+ s0 = s1;
}
} else {
- r0 = null;
- pos = r2;
+ peg$currPos = s0;
+ s0 = peg$c0;
}
- if (r0 !== null) {
- reportedPos = r1;
- r0 = (function(expression) {
- return {
- type: "zero_or_more",
- expression: expression
- };
- })(r3);
- }
- if (r0 === null) {
- pos = r1;
- }
- if (r0 === null) {
- r1 = pos;
- r2 = pos;
- r3 = parse_primary();
- if (r3 !== null) {
- r4 = parse_plus();
- if (r4 !== null) {
- r0 = [r3, r4];
+ } else {
+ peg$currPos = s0;
+ s0 = peg$c0;
+ }
+ if (s0 === null) {
+ s0 = peg$currPos;
+ s1 = peg$parseprimary();
+ if (s1 !== null) {
+ s2 = peg$parseplus();
+ if (s2 !== null) {
+ peg$reportedPos = s0;
+ s1 = peg$c17(s1);
+ if (s1 === null) {
+ peg$currPos = s0;
+ s0 = s1;
} else {
- r0 = null;
- pos = r2;
+ s0 = s1;
}
} else {
- r0 = null;
- pos = r2;
- }
- if (r0 !== null) {
- reportedPos = r1;
- r0 = (function(expression) {
- return {
- type: "one_or_more",
- expression: expression
- };
- })(r3);
- }
- if (r0 === null) {
- pos = r1;
- }
- if (r0 === null) {
- r0 = parse_primary();
- }
- }
- }
- return r0;
- }
-
- function parse_primary() {
- var r0, r1, r2, r3, r4, r5, r6, r7, r8;
-
- r1 = pos;
- r2 = pos;
- r3 = parse_identifier();
- if (r3 !== null) {
- r5 = pos;
- reportFailures++;
- r6 = pos;
- r7 = parse_string();
- r7 = r7 !== null ? r7 : "";
- if (r7 !== null) {
- r8 = parse_equals();
- if (r8 !== null) {
- r4 = [r7, r8];
- } else {
- r4 = null;
- pos = r6;
+ peg$currPos = s0;
+ s0 = peg$c0;
}
} else {
- r4 = null;
- pos = r6;
+ peg$currPos = s0;
+ s0 = peg$c0;
+ }
+ if (s0 === null) {
+ s0 = peg$parseprimary();
}
- reportFailures--;
- if (r4 === null) {
- r4 = "";
+ }
+ }
+
+ return s0;
+ }
+
+ function peg$parseprimary() {
+ var s0, s1, s2, s3, s4, s5;
+
+ s0 = peg$currPos;
+ s1 = peg$parseidentifier();
+ if (s1 !== null) {
+ s2 = peg$currPos;
+ peg$silentFails++;
+ s3 = peg$currPos;
+ s4 = peg$parsestring();
+ if (s4 === null) {
+ s4 = peg$c1;
+ }
+ if (s4 !== null) {
+ s5 = peg$parseequals();
+ if (s5 !== null) {
+ s4 = [s4, s5];
+ s3 = s4;
} else {
- r4 = null;
- pos = r5;
+ peg$currPos = s3;
+ s3 = peg$c0;
}
- if (r4 !== null) {
- r0 = [r3, r4];
+ } else {
+ peg$currPos = s3;
+ s3 = peg$c0;
+ }
+ peg$silentFails--;
+ if (s3 === null) {
+ s2 = peg$c1;
+ } else {
+ peg$currPos = s2;
+ s2 = peg$c0;
+ }
+ if (s2 !== null) {
+ peg$reportedPos = s0;
+ s1 = peg$c18(s1);
+ if (s1 === null) {
+ peg$currPos = s0;
+ s0 = s1;
} else {
- r0 = null;
- pos = r2;
+ s0 = s1;
}
} else {
- r0 = null;
- pos = r2;
+ peg$currPos = s0;
+ s0 = peg$c0;
}
- if (r0 !== null) {
- reportedPos = r1;
- r0 = (function(name) {
- return {
- type: "rule_ref",
- name: name
- };
- })(r3);
- }
- if (r0 === null) {
- pos = r1;
- }
- if (r0 === null) {
- r0 = parse_literal();
- if (r0 === null) {
- r0 = parse_class();
- if (r0 === null) {
- r1 = pos;
- r0 = parse_dot();
- if (r0 !== null) {
- reportedPos = r1;
- r0 = (function() { return { type: "any" }; })();
- }
- if (r0 === null) {
- pos = r1;
- }
- if (r0 === null) {
- r1 = pos;
- r2 = pos;
- r3 = parse_lparen();
- if (r3 !== null) {
- r4 = parse_choice();
- if (r4 !== null) {
- r5 = parse_rparen();
- if (r5 !== null) {
- r0 = [r3, r4, r5];
+ } else {
+ peg$currPos = s0;
+ s0 = peg$c0;
+ }
+ if (s0 === null) {
+ s0 = peg$parseliteral();
+ if (s0 === null) {
+ s0 = peg$parseclass();
+ if (s0 === null) {
+ s0 = peg$currPos;
+ s1 = peg$parsedot();
+ if (s1 !== null) {
+ peg$reportedPos = s0;
+ s1 = peg$c19();
+ }
+ if (s1 === null) {
+ peg$currPos = s0;
+ s0 = s1;
+ } else {
+ s0 = s1;
+ }
+ if (s0 === null) {
+ s0 = peg$currPos;
+ s1 = peg$parselparen();
+ if (s1 !== null) {
+ s2 = peg$parsechoice();
+ if (s2 !== null) {
+ s3 = peg$parserparen();
+ if (s3 !== null) {
+ peg$reportedPos = s0;
+ s1 = peg$c20(s2);
+ if (s1 === null) {
+ peg$currPos = s0;
+ s0 = s1;
} else {
- r0 = null;
- pos = r2;
+ s0 = s1;
}
} else {
- r0 = null;
- pos = r2;
+ peg$currPos = s0;
+ s0 = peg$c0;
}
} else {
- r0 = null;
- pos = r2;
- }
- if (r0 !== null) {
- reportedPos = r1;
- r0 = (function(expression) { return expression; })(r4);
- }
- if (r0 === null) {
- pos = r1;
+ peg$currPos = s0;
+ s0 = peg$c0;
}
+ } else {
+ peg$currPos = s0;
+ s0 = peg$c0;
}
}
}
}
- return r0;
}
-
- function parse_action() {
- var r0, r1, r2, r3, r4;
-
- reportFailures++;
- r1 = pos;
- r2 = pos;
- r3 = parse_braced();
- if (r3 !== null) {
- r4 = parse___();
- if (r4 !== null) {
- r0 = [r3, r4];
- } else {
- r0 = null;
- pos = r2;
- }
- } else {
- r0 = null;
- pos = r2;
- }
- if (r0 !== null) {
- reportedPos = r1;
- r0 = (function(braced) { return braced.substr(1, braced.length - 2); })(r3);
- }
- if (r0 === null) {
- pos = r1;
- }
- reportFailures--;
- if (reportFailures === 0 && r0 === null) {
- matchFailed("action");
+
+ return s0;
+ }
+
+ function peg$parseaction() {
+ var s0, s1, s2;
+
+ peg$silentFails++;
+ s0 = peg$currPos;
+ s1 = peg$parsebraced();
+ if (s1 !== null) {
+ s2 = peg$parse__();
+ if (s2 !== null) {
+ peg$reportedPos = s0;
+ s1 = peg$c22(s1);
+ if (s1 === null) {
+ peg$currPos = s0;
+ s0 = s1;
+ } else {
+ s0 = s1;
+ }
+ } else {
+ peg$currPos = s0;
+ s0 = peg$c0;
}
- return r0;
+ } else {
+ peg$currPos = s0;
+ s0 = peg$c0;
}
-
- function parse_braced() {
- var r0, r1, r2, r3, r4, r5;
-
- r1 = pos;
- r2 = pos;
- if (input.charCodeAt(pos) === 123) {
- r3 = "{";
- pos++;
- } else {
- r3 = null;
- if (reportFailures === 0) {
- matchFailed("\"{\"");
- }
+ peg$silentFails--;
+ if (s0 === null) {
+ s1 = null;
+ if (peg$silentFails === 0) { peg$fail(peg$c21); }
+ }
+
+ return s0;
+ }
+
+ function peg$parsebraced() {
+ var s0, s1, s2, s3, s4;
+
+ s0 = peg$currPos;
+ s1 = peg$currPos;
+ if (input.charCodeAt(peg$currPos) === 123) {
+ s2 = peg$c23;
+ peg$currPos++;
+ } else {
+ s2 = null;
+ if (peg$silentFails === 0) { peg$fail(peg$c24); }
+ }
+ if (s2 !== null) {
+ s3 = [];
+ s4 = peg$parsebraced();
+ if (s4 === null) {
+ s4 = peg$parsenonBraceCharacters();
}
- if (r3 !== null) {
- r4 = [];
- r5 = parse_braced();
- if (r5 === null) {
- r5 = parse_nonBraceCharacters();
+ while (s4 !== null) {
+ s3.push(s4);
+ s4 = peg$parsebraced();
+ if (s4 === null) {
+ s4 = peg$parsenonBraceCharacters();
}
- while (r5 !== null) {
- r4.push(r5);
- r5 = parse_braced();
- if (r5 === null) {
- r5 = parse_nonBraceCharacters();
- }
+ }
+ if (s3 !== null) {
+ if (input.charCodeAt(peg$currPos) === 125) {
+ s4 = peg$c25;
+ peg$currPos++;
+ } else {
+ s4 = null;
+ if (peg$silentFails === 0) { peg$fail(peg$c26); }
}
- if (r4 !== null) {
- if (input.charCodeAt(pos) === 125) {
- r5 = "}";
- pos++;
- } else {
- r5 = null;
- if (reportFailures === 0) {
- matchFailed("\"}\"");
- }
- }
- if (r5 !== null) {
- r0 = [r3, r4, r5];
- } else {
- r0 = null;
- pos = r2;
- }
+ if (s4 !== null) {
+ s2 = [s2, s3, s4];
+ s1 = s2;
} else {
- r0 = null;
- pos = r2;
+ peg$currPos = s1;
+ s1 = peg$c0;
}
} else {
- r0 = null;
- pos = r2;
- }
- if (r0 !== null) {
- r0 = input.substring(pos, r1);
+ peg$currPos = s1;
+ s1 = peg$c0;
}
- return r0;
+ } else {
+ peg$currPos = s1;
+ s1 = peg$c0;
}
-
- function parse_nonBraceCharacters() {
- var r0, r1;
-
- r1 = parse_nonBraceCharacter();
- if (r1 !== null) {
- r0 = [];
- while (r1 !== null) {
- r0.push(r1);
- r1 = parse_nonBraceCharacter();
- }
- } else {
- r0 = null;
- }
- return r0;
+ if (s1 !== null) {
+ s1 = input.substring(s0, peg$currPos);
}
-
- function parse_nonBraceCharacter() {
- var r0;
-
- if (/^[^{}]/.test(input.charAt(pos))) {
- r0 = input.charAt(pos);
- pos++;
- } else {
- r0 = null;
- if (reportFailures === 0) {
- matchFailed("[^{}]");
- }
+ s0 = s1;
+
+ return s0;
+ }
+
+ function peg$parsenonBraceCharacters() {
+ var s0, s1;
+
+ s0 = [];
+ s1 = peg$parsenonBraceCharacter();
+ if (s1 !== null) {
+ while (s1 !== null) {
+ s0.push(s1);
+ s1 = peg$parsenonBraceCharacter();
}
- return r0;
+ } else {
+ s0 = peg$c0;
}
-
- function parse_equals() {
- var r0, r1, r2, r3, r4;
-
- r1 = pos;
- r2 = pos;
- if (input.charCodeAt(pos) === 61) {
- r3 = "=";
- pos++;
- } else {
- r3 = null;
- if (reportFailures === 0) {
- matchFailed("\"=\"");
- }
- }
- if (r3 !== null) {
- r4 = parse___();
- if (r4 !== null) {
- r0 = [r3, r4];
+
+ return s0;
+ }
+
+ function peg$parsenonBraceCharacter() {
+ var s0;
+
+ if (peg$c27.test(input.charAt(peg$currPos))) {
+ s0 = input.charAt(peg$currPos);
+ peg$currPos++;
+ } else {
+ s0 = null;
+ if (peg$silentFails === 0) { peg$fail(peg$c28); }
+ }
+
+ return s0;
+ }
+
+ function peg$parseequals() {
+ var s0, s1, s2;
+
+ s0 = peg$currPos;
+ if (input.charCodeAt(peg$currPos) === 61) {
+ s1 = peg$c29;
+ peg$currPos++;
+ } else {
+ s1 = null;
+ if (peg$silentFails === 0) { peg$fail(peg$c30); }
+ }
+ if (s1 !== null) {
+ s2 = peg$parse__();
+ if (s2 !== null) {
+ peg$reportedPos = s0;
+ s1 = peg$c31();
+ if (s1 === null) {
+ peg$currPos = s0;
+ s0 = s1;
} else {
- r0 = null;
- pos = r2;
+ s0 = s1;
}
} else {
- r0 = null;
- pos = r2;
- }
- if (r0 !== null) {
- reportedPos = r1;
- r0 = (function() { return "="; })();
+ peg$currPos = s0;
+ s0 = peg$c0;
}
- if (r0 === null) {
- pos = r1;
- }
- return r0;
+ } else {
+ peg$currPos = s0;
+ s0 = peg$c0;
}
-
- function parse_colon() {
- var r0, r1, r2, r3, r4;
-
- r1 = pos;
- r2 = pos;
- if (input.charCodeAt(pos) === 58) {
- r3 = ":";
- pos++;
- } else {
- r3 = null;
- if (reportFailures === 0) {
- matchFailed("\":\"");
- }
- }
- if (r3 !== null) {
- r4 = parse___();
- if (r4 !== null) {
- r0 = [r3, r4];
+
+ return s0;
+ }
+
+ function peg$parsecolon() {
+ var s0, s1, s2;
+
+ s0 = peg$currPos;
+ if (input.charCodeAt(peg$currPos) === 58) {
+ s1 = peg$c32;
+ peg$currPos++;
+ } else {
+ s1 = null;
+ if (peg$silentFails === 0) { peg$fail(peg$c33); }
+ }
+ if (s1 !== null) {
+ s2 = peg$parse__();
+ if (s2 !== null) {
+ peg$reportedPos = s0;
+ s1 = peg$c34();
+ if (s1 === null) {
+ peg$currPos = s0;
+ s0 = s1;
} else {
- r0 = null;
- pos = r2;
+ s0 = s1;
}
} else {
- r0 = null;
- pos = r2;
- }
- if (r0 !== null) {
- reportedPos = r1;
- r0 = (function() { return ":"; })();
- }
- if (r0 === null) {
- pos = r1;
+ peg$currPos = s0;
+ s0 = peg$c0;
}
- return r0;
+ } else {
+ peg$currPos = s0;
+ s0 = peg$c0;
}
-
- function parse_semicolon() {
- var r0, r1, r2, r3, r4;
-
- r1 = pos;
- r2 = pos;
- if (input.charCodeAt(pos) === 59) {
- r3 = ";";
- pos++;
- } else {
- r3 = null;
- if (reportFailures === 0) {
- matchFailed("\";\"");
- }
- }
- if (r3 !== null) {
- r4 = parse___();
- if (r4 !== null) {
- r0 = [r3, r4];
+
+ return s0;
+ }
+
+ function peg$parsesemicolon() {
+ var s0, s1, s2;
+
+ s0 = peg$currPos;
+ if (input.charCodeAt(peg$currPos) === 59) {
+ s1 = peg$c35;
+ peg$currPos++;
+ } else {
+ s1 = null;
+ if (peg$silentFails === 0) { peg$fail(peg$c36); }
+ }
+ if (s1 !== null) {
+ s2 = peg$parse__();
+ if (s2 !== null) {
+ peg$reportedPos = s0;
+ s1 = peg$c37();
+ if (s1 === null) {
+ peg$currPos = s0;
+ s0 = s1;
} else {
- r0 = null;
- pos = r2;
+ s0 = s1;
}
} else {
- r0 = null;
- pos = r2;
- }
- if (r0 !== null) {
- reportedPos = r1;
- r0 = (function() { return ";"; })();
+ peg$currPos = s0;
+ s0 = peg$c0;
}
- if (r0 === null) {
- pos = r1;
- }
- return r0;
+ } else {
+ peg$currPos = s0;
+ s0 = peg$c0;
}
-
- function parse_slash() {
- var r0, r1, r2, r3, r4;
-
- r1 = pos;
- r2 = pos;
- if (input.charCodeAt(pos) === 47) {
- r3 = "/";
- pos++;
- } else {
- r3 = null;
- if (reportFailures === 0) {
- matchFailed("\"/\"");
- }
- }
- if (r3 !== null) {
- r4 = parse___();
- if (r4 !== null) {
- r0 = [r3, r4];
+
+ return s0;
+ }
+
+ function peg$parseslash() {
+ var s0, s1, s2;
+
+ s0 = peg$currPos;
+ if (input.charCodeAt(peg$currPos) === 47) {
+ s1 = peg$c38;
+ peg$currPos++;
+ } else {
+ s1 = null;
+ if (peg$silentFails === 0) { peg$fail(peg$c39); }
+ }
+ if (s1 !== null) {
+ s2 = peg$parse__();
+ if (s2 !== null) {
+ peg$reportedPos = s0;
+ s1 = peg$c40();
+ if (s1 === null) {
+ peg$currPos = s0;
+ s0 = s1;
} else {
- r0 = null;
- pos = r2;
+ s0 = s1;
}
} else {
- r0 = null;
- pos = r2;
+ peg$currPos = s0;
+ s0 = peg$c0;
}
- if (r0 !== null) {
- reportedPos = r1;
- r0 = (function() { return "/"; })();
- }
- if (r0 === null) {
- pos = r1;
- }
- return r0;
+ } else {
+ peg$currPos = s0;
+ s0 = peg$c0;
}
-
- function parse_and() {
- var r0, r1, r2, r3, r4;
-
- r1 = pos;
- r2 = pos;
- if (input.charCodeAt(pos) === 38) {
- r3 = "&";
- pos++;
- } else {
- r3 = null;
- if (reportFailures === 0) {
- matchFailed("\"&\"");
- }
- }
- if (r3 !== null) {
- r4 = parse___();
- if (r4 !== null) {
- r0 = [r3, r4];
+
+ return s0;
+ }
+
+ function peg$parseand() {
+ var s0, s1, s2;
+
+ s0 = peg$currPos;
+ if (input.charCodeAt(peg$currPos) === 38) {
+ s1 = peg$c41;
+ peg$currPos++;
+ } else {
+ s1 = null;
+ if (peg$silentFails === 0) { peg$fail(peg$c42); }
+ }
+ if (s1 !== null) {
+ s2 = peg$parse__();
+ if (s2 !== null) {
+ peg$reportedPos = s0;
+ s1 = peg$c43();
+ if (s1 === null) {
+ peg$currPos = s0;
+ s0 = s1;
} else {
- r0 = null;
- pos = r2;
+ s0 = s1;
}
} else {
- r0 = null;
- pos = r2;
- }
- if (r0 !== null) {
- reportedPos = r1;
- r0 = (function() { return "&"; })();
+ peg$currPos = s0;
+ s0 = peg$c0;
}
- if (r0 === null) {
- pos = r1;
- }
- return r0;
+ } else {
+ peg$currPos = s0;
+ s0 = peg$c0;
}
-
- function parse_not() {
- var r0, r1, r2, r3, r4;
-
- r1 = pos;
- r2 = pos;
- if (input.charCodeAt(pos) === 33) {
- r3 = "!";
- pos++;
- } else {
- r3 = null;
- if (reportFailures === 0) {
- matchFailed("\"!\"");
- }
- }
- if (r3 !== null) {
- r4 = parse___();
- if (r4 !== null) {
- r0 = [r3, r4];
+
+ return s0;
+ }
+
+ function peg$parsenot() {
+ var s0, s1, s2;
+
+ s0 = peg$currPos;
+ if (input.charCodeAt(peg$currPos) === 33) {
+ s1 = peg$c44;
+ peg$currPos++;
+ } else {
+ s1 = null;
+ if (peg$silentFails === 0) { peg$fail(peg$c45); }
+ }
+ if (s1 !== null) {
+ s2 = peg$parse__();
+ if (s2 !== null) {
+ peg$reportedPos = s0;
+ s1 = peg$c46();
+ if (s1 === null) {
+ peg$currPos = s0;
+ s0 = s1;
} else {
- r0 = null;
- pos = r2;
+ s0 = s1;
}
} else {
- r0 = null;
- pos = r2;
- }
- if (r0 !== null) {
- reportedPos = r1;
- r0 = (function() { return "!"; })();
- }
- if (r0 === null) {
- pos = r1;
+ peg$currPos = s0;
+ s0 = peg$c0;
}
- return r0;
+ } else {
+ peg$currPos = s0;
+ s0 = peg$c0;
}
-
- function parse_dollar() {
- var r0, r1, r2, r3, r4;
-
- r1 = pos;
- r2 = pos;
- if (input.charCodeAt(pos) === 36) {
- r3 = "$";
- pos++;
- } else {
- r3 = null;
- if (reportFailures === 0) {
- matchFailed("\"$\"");
- }
- }
- if (r3 !== null) {
- r4 = parse___();
- if (r4 !== null) {
- r0 = [r3, r4];
+
+ return s0;
+ }
+
+ function peg$parsedollar() {
+ var s0, s1, s2;
+
+ s0 = peg$currPos;
+ if (input.charCodeAt(peg$currPos) === 36) {
+ s1 = peg$c47;
+ peg$currPos++;
+ } else {
+ s1 = null;
+ if (peg$silentFails === 0) { peg$fail(peg$c48); }
+ }
+ if (s1 !== null) {
+ s2 = peg$parse__();
+ if (s2 !== null) {
+ peg$reportedPos = s0;
+ s1 = peg$c49();
+ if (s1 === null) {
+ peg$currPos = s0;
+ s0 = s1;
} else {
- r0 = null;
- pos = r2;
+ s0 = s1;
}
} else {
- r0 = null;
- pos = r2;
- }
- if (r0 !== null) {
- reportedPos = r1;
- r0 = (function() { return "$"; })();
+ peg$currPos = s0;
+ s0 = peg$c0;
}
- if (r0 === null) {
- pos = r1;
- }
- return r0;
+ } else {
+ peg$currPos = s0;
+ s0 = peg$c0;
}
-
- function parse_question() {
- var r0, r1, r2, r3, r4;
-
- r1 = pos;
- r2 = pos;
- if (input.charCodeAt(pos) === 63) {
- r3 = "?";
- pos++;
- } else {
- r3 = null;
- if (reportFailures === 0) {
- matchFailed("\"?\"");
- }
- }
- if (r3 !== null) {
- r4 = parse___();
- if (r4 !== null) {
- r0 = [r3, r4];
+
+ return s0;
+ }
+
+ function peg$parsequestion() {
+ var s0, s1, s2;
+
+ s0 = peg$currPos;
+ if (input.charCodeAt(peg$currPos) === 63) {
+ s1 = peg$c50;
+ peg$currPos++;
+ } else {
+ s1 = null;
+ if (peg$silentFails === 0) { peg$fail(peg$c51); }
+ }
+ if (s1 !== null) {
+ s2 = peg$parse__();
+ if (s2 !== null) {
+ peg$reportedPos = s0;
+ s1 = peg$c52();
+ if (s1 === null) {
+ peg$currPos = s0;
+ s0 = s1;
} else {
- r0 = null;
- pos = r2;
+ s0 = s1;
}
} else {
- r0 = null;
- pos = r2;
+ peg$currPos = s0;
+ s0 = peg$c0;
}
- if (r0 !== null) {
- reportedPos = r1;
- r0 = (function() { return "?"; })();
- }
- if (r0 === null) {
- pos = r1;
- }
- return r0;
+ } else {
+ peg$currPos = s0;
+ s0 = peg$c0;
}
-
- function parse_star() {
- var r0, r1, r2, r3, r4;
-
- r1 = pos;
- r2 = pos;
- if (input.charCodeAt(pos) === 42) {
- r3 = "*";
- pos++;
- } else {
- r3 = null;
- if (reportFailures === 0) {
- matchFailed("\"*\"");
- }
- }
- if (r3 !== null) {
- r4 = parse___();
- if (r4 !== null) {
- r0 = [r3, r4];
+
+ return s0;
+ }
+
+ function peg$parsestar() {
+ var s0, s1, s2;
+
+ s0 = peg$currPos;
+ if (input.charCodeAt(peg$currPos) === 42) {
+ s1 = peg$c53;
+ peg$currPos++;
+ } else {
+ s1 = null;
+ if (peg$silentFails === 0) { peg$fail(peg$c54); }
+ }
+ if (s1 !== null) {
+ s2 = peg$parse__();
+ if (s2 !== null) {
+ peg$reportedPos = s0;
+ s1 = peg$c55();
+ if (s1 === null) {
+ peg$currPos = s0;
+ s0 = s1;
} else {
- r0 = null;
- pos = r2;
+ s0 = s1;
}
} else {
- r0 = null;
- pos = r2;
- }
- if (r0 !== null) {
- reportedPos = r1;
- r0 = (function() { return "*"; })();
+ peg$currPos = s0;
+ s0 = peg$c0;
}
- if (r0 === null) {
- pos = r1;
- }
- return r0;
+ } else {
+ peg$currPos = s0;
+ s0 = peg$c0;
}
-
- function parse_plus() {
- var r0, r1, r2, r3, r4;
-
- r1 = pos;
- r2 = pos;
- if (input.charCodeAt(pos) === 43) {
- r3 = "+";
- pos++;
- } else {
- r3 = null;
- if (reportFailures === 0) {
- matchFailed("\"+\"");
- }
- }
- if (r3 !== null) {
- r4 = parse___();
- if (r4 !== null) {
- r0 = [r3, r4];
+
+ return s0;
+ }
+
+ function peg$parseplus() {
+ var s0, s1, s2;
+
+ s0 = peg$currPos;
+ if (input.charCodeAt(peg$currPos) === 43) {
+ s1 = peg$c56;
+ peg$currPos++;
+ } else {
+ s1 = null;
+ if (peg$silentFails === 0) { peg$fail(peg$c57); }
+ }
+ if (s1 !== null) {
+ s2 = peg$parse__();
+ if (s2 !== null) {
+ peg$reportedPos = s0;
+ s1 = peg$c58();
+ if (s1 === null) {
+ peg$currPos = s0;
+ s0 = s1;
} else {
- r0 = null;
- pos = r2;
+ s0 = s1;
}
} else {
- r0 = null;
- pos = r2;
- }
- if (r0 !== null) {
- reportedPos = r1;
- r0 = (function() { return "+"; })();
- }
- if (r0 === null) {
- pos = r1;
+ peg$currPos = s0;
+ s0 = peg$c0;
}
- return r0;
+ } else {
+ peg$currPos = s0;
+ s0 = peg$c0;
}
-
- function parse_lparen() {
- var r0, r1, r2, r3, r4;
-
- r1 = pos;
- r2 = pos;
- if (input.charCodeAt(pos) === 40) {
- r3 = "(";
- pos++;
- } else {
- r3 = null;
- if (reportFailures === 0) {
- matchFailed("\"(\"");
- }
- }
- if (r3 !== null) {
- r4 = parse___();
- if (r4 !== null) {
- r0 = [r3, r4];
+
+ return s0;
+ }
+
+ function peg$parselparen() {
+ var s0, s1, s2;
+
+ s0 = peg$currPos;
+ if (input.charCodeAt(peg$currPos) === 40) {
+ s1 = peg$c59;
+ peg$currPos++;
+ } else {
+ s1 = null;
+ if (peg$silentFails === 0) { peg$fail(peg$c60); }
+ }
+ if (s1 !== null) {
+ s2 = peg$parse__();
+ if (s2 !== null) {
+ peg$reportedPos = s0;
+ s1 = peg$c61();
+ if (s1 === null) {
+ peg$currPos = s0;
+ s0 = s1;
} else {
- r0 = null;
- pos = r2;
+ s0 = s1;
}
} else {
- r0 = null;
- pos = r2;
- }
- if (r0 !== null) {
- reportedPos = r1;
- r0 = (function() { return "("; })();
+ peg$currPos = s0;
+ s0 = peg$c0;
}
- if (r0 === null) {
- pos = r1;
- }
- return r0;
+ } else {
+ peg$currPos = s0;
+ s0 = peg$c0;
}
-
- function parse_rparen() {
- var r0, r1, r2, r3, r4;
-
- r1 = pos;
- r2 = pos;
- if (input.charCodeAt(pos) === 41) {
- r3 = ")";
- pos++;
- } else {
- r3 = null;
- if (reportFailures === 0) {
- matchFailed("\")\"");
- }
- }
- if (r3 !== null) {
- r4 = parse___();
- if (r4 !== null) {
- r0 = [r3, r4];
+
+ return s0;
+ }
+
+ function peg$parserparen() {
+ var s0, s1, s2;
+
+ s0 = peg$currPos;
+ if (input.charCodeAt(peg$currPos) === 41) {
+ s1 = peg$c62;
+ peg$currPos++;
+ } else {
+ s1 = null;
+ if (peg$silentFails === 0) { peg$fail(peg$c63); }
+ }
+ if (s1 !== null) {
+ s2 = peg$parse__();
+ if (s2 !== null) {
+ peg$reportedPos = s0;
+ s1 = peg$c64();
+ if (s1 === null) {
+ peg$currPos = s0;
+ s0 = s1;
} else {
- r0 = null;
- pos = r2;
+ s0 = s1;
}
} else {
- r0 = null;
- pos = r2;
+ peg$currPos = s0;
+ s0 = peg$c0;
}
- if (r0 !== null) {
- reportedPos = r1;
- r0 = (function() { return ")"; })();
- }
- if (r0 === null) {
- pos = r1;
- }
- return r0;
+ } else {
+ peg$currPos = s0;
+ s0 = peg$c0;
}
-
- function parse_dot() {
- var r0, r1, r2, r3, r4;
-
- r1 = pos;
- r2 = pos;
- if (input.charCodeAt(pos) === 46) {
- r3 = ".";
- pos++;
- } else {
- r3 = null;
- if (reportFailures === 0) {
- matchFailed("\".\"");
- }
- }
- if (r3 !== null) {
- r4 = parse___();
- if (r4 !== null) {
- r0 = [r3, r4];
+
+ return s0;
+ }
+
+ function peg$parsedot() {
+ var s0, s1, s2;
+
+ s0 = peg$currPos;
+ if (input.charCodeAt(peg$currPos) === 46) {
+ s1 = peg$c65;
+ peg$currPos++;
+ } else {
+ s1 = null;
+ if (peg$silentFails === 0) { peg$fail(peg$c66); }
+ }
+ if (s1 !== null) {
+ s2 = peg$parse__();
+ if (s2 !== null) {
+ peg$reportedPos = s0;
+ s1 = peg$c67();
+ if (s1 === null) {
+ peg$currPos = s0;
+ s0 = s1;
} else {
- r0 = null;
- pos = r2;
+ s0 = s1;
}
} else {
- r0 = null;
- pos = r2;
- }
- if (r0 !== null) {
- reportedPos = r1;
- r0 = (function() { return "."; })();
+ peg$currPos = s0;
+ s0 = peg$c0;
}
- if (r0 === null) {
- pos = r1;
- }
- return r0;
+ } else {
+ peg$currPos = s0;
+ s0 = peg$c0;
}
-
- function parse_identifier() {
- var r0, r1, r2, r3, r4, r5, r6, r7, r8;
-
- reportFailures++;
- r1 = pos;
- r2 = pos;
- r4 = pos;
- r5 = pos;
- r6 = parse_letter();
- if (r6 === null) {
- if (input.charCodeAt(pos) === 95) {
- r6 = "_";
- pos++;
- } else {
- r6 = null;
- if (reportFailures === 0) {
- matchFailed("\"_\"");
+
+ return s0;
+ }
+
+ function peg$parseidentifier() {
+ var s0, s1, s2, s3, s4, s5;
+
+ peg$silentFails++;
+ s0 = peg$currPos;
+ s1 = peg$currPos;
+ s2 = peg$currPos;
+ s3 = peg$parseletter();
+ if (s3 === null) {
+ if (input.charCodeAt(peg$currPos) === 95) {
+ s3 = peg$c69;
+ peg$currPos++;
+ } else {
+ s3 = null;
+ if (peg$silentFails === 0) { peg$fail(peg$c70); }
+ }
+ }
+ if (s3 !== null) {
+ s4 = [];
+ s5 = peg$parseletter();
+ if (s5 === null) {
+ s5 = peg$parsedigit();
+ if (s5 === null) {
+ if (input.charCodeAt(peg$currPos) === 95) {
+ s5 = peg$c69;
+ peg$currPos++;
+ } else {
+ s5 = null;
+ if (peg$silentFails === 0) { peg$fail(peg$c70); }
}
}
}
- if (r6 !== null) {
- r7 = [];
- r8 = parse_letter();
- if (r8 === null) {
- r8 = parse_digit();
- if (r8 === null) {
- if (input.charCodeAt(pos) === 95) {
- r8 = "_";
- pos++;
+ while (s5 !== null) {
+ s4.push(s5);
+ s5 = peg$parseletter();
+ if (s5 === null) {
+ s5 = peg$parsedigit();
+ if (s5 === null) {
+ if (input.charCodeAt(peg$currPos) === 95) {
+ s5 = peg$c69;
+ peg$currPos++;
} else {
- r8 = null;
- if (reportFailures === 0) {
- matchFailed("\"_\"");
- }
+ s5 = null;
+ if (peg$silentFails === 0) { peg$fail(peg$c70); }
}
}
}
- while (r8 !== null) {
- r7.push(r8);
- r8 = parse_letter();
- if (r8 === null) {
- r8 = parse_digit();
- if (r8 === null) {
- if (input.charCodeAt(pos) === 95) {
- r8 = "_";
- pos++;
- } else {
- r8 = null;
- if (reportFailures === 0) {
- matchFailed("\"_\"");
- }
- }
- }
- }
- }
- if (r7 !== null) {
- r3 = [r6, r7];
- } else {
- r3 = null;
- pos = r5;
- }
- } else {
- r3 = null;
- pos = r5;
}
- if (r3 !== null) {
- r3 = input.substring(pos, r4);
+ if (s4 !== null) {
+ s3 = [s3, s4];
+ s2 = s3;
+ } else {
+ peg$currPos = s2;
+ s2 = peg$c0;
}
- if (r3 !== null) {
- r4 = parse___();
- if (r4 !== null) {
- r0 = [r3, r4];
+ } else {
+ peg$currPos = s2;
+ s2 = peg$c0;
+ }
+ if (s2 !== null) {
+ s2 = input.substring(s1, peg$currPos);
+ }
+ s1 = s2;
+ if (s1 !== null) {
+ s2 = peg$parse__();
+ if (s2 !== null) {
+ peg$reportedPos = s0;
+ s1 = peg$c71(s1);
+ if (s1 === null) {
+ peg$currPos = s0;
+ s0 = s1;
} else {
- r0 = null;
- pos = r2;
+ s0 = s1;
}
} else {
- r0 = null;
- pos = r2;
- }
- if (r0 !== null) {
- reportedPos = r1;
- r0 = (function(chars) { return chars; })(r3);
- }
- if (r0 === null) {
- pos = r1;
- }
- reportFailures--;
- if (reportFailures === 0 && r0 === null) {
- matchFailed("identifier");
+ peg$currPos = s0;
+ s0 = peg$c0;
}
- return r0;
+ } else {
+ peg$currPos = s0;
+ s0 = peg$c0;
}
-
- function parse_literal() {
- var r0, r1, r2, r3, r4, r5;
-
- reportFailures++;
- r1 = pos;
- r2 = pos;
- r3 = parse_doubleQuotedString();
- if (r3 === null) {
- r3 = parse_singleQuotedString();
- }
- if (r3 !== null) {
- if (input.charCodeAt(pos) === 105) {
- r4 = "i";
- pos++;
- } else {
- r4 = null;
- if (reportFailures === 0) {
- matchFailed("\"i\"");
- }
- }
- r4 = r4 !== null ? r4 : "";
- if (r4 !== null) {
- r5 = parse___();
- if (r5 !== null) {
- r0 = [r3, r4, r5];
+ peg$silentFails--;
+ if (s0 === null) {
+ s1 = null;
+ if (peg$silentFails === 0) { peg$fail(peg$c68); }
+ }
+
+ return s0;
+ }
+
+ function peg$parseliteral() {
+ var s0, s1, s2, s3;
+
+ peg$silentFails++;
+ s0 = peg$currPos;
+ s1 = peg$parsedoubleQuotedString();
+ if (s1 === null) {
+ s1 = peg$parsesingleQuotedString();
+ }
+ if (s1 !== null) {
+ if (input.charCodeAt(peg$currPos) === 105) {
+ s2 = peg$c73;
+ peg$currPos++;
+ } else {
+ s2 = null;
+ if (peg$silentFails === 0) { peg$fail(peg$c74); }
+ }
+ if (s2 === null) {
+ s2 = peg$c1;
+ }
+ if (s2 !== null) {
+ s3 = peg$parse__();
+ if (s3 !== null) {
+ peg$reportedPos = s0;
+ s1 = peg$c75(s1,s2);
+ if (s1 === null) {
+ peg$currPos = s0;
+ s0 = s1;
} else {
- r0 = null;
- pos = r2;
+ s0 = s1;
}
} else {
- r0 = null;
- pos = r2;
+ peg$currPos = s0;
+ s0 = peg$c0;
}
} else {
- r0 = null;
- pos = r2;
+ peg$currPos = s0;
+ s0 = peg$c0;
}
- if (r0 !== null) {
- reportedPos = r1;
- r0 = (function(value, flags) {
- return {
- type: "literal",
- value: value,
- ignoreCase: flags === "i"
- };
- })(r3, r4);
- }
- if (r0 === null) {
- pos = r1;
- }
- reportFailures--;
- if (reportFailures === 0 && r0 === null) {
- matchFailed("literal");
- }
- return r0;
- }
-
- function parse_string() {
- var r0, r1, r2, r3, r4;
-
- reportFailures++;
- r1 = pos;
- r2 = pos;
- r3 = parse_doubleQuotedString();
- if (r3 === null) {
- r3 = parse_singleQuotedString();
- }
- if (r3 !== null) {
- r4 = parse___();
- if (r4 !== null) {
- r0 = [r3, r4];
- } else {
- r0 = null;
- pos = r2;
- }
- } else {
- r0 = null;
- pos = r2;
- }
- if (r0 !== null) {
- reportedPos = r1;
- r0 = (function(string) { return string; })(r3);
- }
- if (r0 === null) {
- pos = r1;
- }
- reportFailures--;
- if (reportFailures === 0 && r0 === null) {
- matchFailed("string");
- }
- return r0;
- }
-
- function parse_doubleQuotedString() {
- var r0, r1, r2, r3, r4, r5;
-
- r1 = pos;
- r2 = pos;
- if (input.charCodeAt(pos) === 34) {
- r3 = "\"";
- pos++;
- } else {
- r3 = null;
- if (reportFailures === 0) {
- matchFailed("\"\\\"\"");
- }
- }
- if (r3 !== null) {
- r4 = [];
- r5 = parse_doubleQuotedCharacter();
- while (r5 !== null) {
- r4.push(r5);
- r5 = parse_doubleQuotedCharacter();
- }
- if (r4 !== null) {
- if (input.charCodeAt(pos) === 34) {
- r5 = "\"";
- pos++;
- } else {
- r5 = null;
- if (reportFailures === 0) {
- matchFailed("\"\\\"\"");
- }
- }
- if (r5 !== null) {
- r0 = [r3, r4, r5];
+ } else {
+ peg$currPos = s0;
+ s0 = peg$c0;
+ }
+ peg$silentFails--;
+ if (s0 === null) {
+ s1 = null;
+ if (peg$silentFails === 0) { peg$fail(peg$c72); }
+ }
+
+ return s0;
+ }
+
+ function peg$parsestring() {
+ var s0, s1, s2;
+
+ peg$silentFails++;
+ s0 = peg$currPos;
+ s1 = peg$parsedoubleQuotedString();
+ if (s1 === null) {
+ s1 = peg$parsesingleQuotedString();
+ }
+ if (s1 !== null) {
+ s2 = peg$parse__();
+ if (s2 !== null) {
+ peg$reportedPos = s0;
+ s1 = peg$c77(s1);
+ if (s1 === null) {
+ peg$currPos = s0;
+ s0 = s1;
+ } else {
+ s0 = s1;
+ }
+ } else {
+ peg$currPos = s0;
+ s0 = peg$c0;
+ }
+ } else {
+ peg$currPos = s0;
+ s0 = peg$c0;
+ }
+ peg$silentFails--;
+ if (s0 === null) {
+ s1 = null;
+ if (peg$silentFails === 0) { peg$fail(peg$c76); }
+ }
+
+ return s0;
+ }
+
+ function peg$parsedoubleQuotedString() {
+ var s0, s1, s2, s3;
+
+ s0 = peg$currPos;
+ if (input.charCodeAt(peg$currPos) === 34) {
+ s1 = peg$c78;
+ peg$currPos++;
+ } else {
+ s1 = null;
+ if (peg$silentFails === 0) { peg$fail(peg$c79); }
+ }
+ if (s1 !== null) {
+ s2 = [];
+ s3 = peg$parsedoubleQuotedCharacter();
+ while (s3 !== null) {
+ s2.push(s3);
+ s3 = peg$parsedoubleQuotedCharacter();
+ }
+ if (s2 !== null) {
+ if (input.charCodeAt(peg$currPos) === 34) {
+ s3 = peg$c78;
+ peg$currPos++;
+ } else {
+ s3 = null;
+ if (peg$silentFails === 0) { peg$fail(peg$c79); }
+ }
+ if (s3 !== null) {
+ peg$reportedPos = s0;
+ s1 = peg$c80(s2);
+ if (s1 === null) {
+ peg$currPos = s0;
+ s0 = s1;
} else {
- r0 = null;
- pos = r2;
+ s0 = s1;
}
} else {
- r0 = null;
- pos = r2;
- }
- } else {
- r0 = null;
- pos = r2;
- }
- if (r0 !== null) {
- reportedPos = r1;
- r0 = (function(chars) { return chars.join(""); })(r4);
- }
- if (r0 === null) {
- pos = r1;
- }
- return r0;
- }
-
- function parse_doubleQuotedCharacter() {
- var r0;
-
- r0 = parse_simpleDoubleQuotedCharacter();
- if (r0 === null) {
- r0 = parse_simpleEscapeSequence();
- if (r0 === null) {
- r0 = parse_zeroEscapeSequence();
- if (r0 === null) {
- r0 = parse_hexEscapeSequence();
- if (r0 === null) {
- r0 = parse_unicodeEscapeSequence();
- if (r0 === null) {
- r0 = parse_eolEscapeSequence();
- }
+ peg$currPos = s0;
+ s0 = peg$c0;
+ }
+ } else {
+ peg$currPos = s0;
+ s0 = peg$c0;
+ }
+ } else {
+ peg$currPos = s0;
+ s0 = peg$c0;
+ }
+
+ return s0;
+ }
+
+ function peg$parsedoubleQuotedCharacter() {
+ var s0;
+
+ s0 = peg$parsesimpleDoubleQuotedCharacter();
+ if (s0 === null) {
+ s0 = peg$parsesimpleEscapeSequence();
+ if (s0 === null) {
+ s0 = peg$parsezeroEscapeSequence();
+ if (s0 === null) {
+ s0 = peg$parsehexEscapeSequence();
+ if (s0 === null) {
+ s0 = peg$parseunicodeEscapeSequence();
+ if (s0 === null) {
+ s0 = peg$parseeolEscapeSequence();
}
}
}
}
- return r0;
}
-
- function parse_simpleDoubleQuotedCharacter() {
- var r0, r1, r2, r3, r4;
-
- r1 = pos;
- r2 = pos;
- r4 = pos;
- reportFailures++;
- if (input.charCodeAt(pos) === 34) {
- r3 = "\"";
- pos++;
+
+ return s0;
+ }
+
+ function peg$parsesimpleDoubleQuotedCharacter() {
+ var s0, s1, s2;
+
+ s0 = peg$currPos;
+ s1 = peg$currPos;
+ peg$silentFails++;
+ if (input.charCodeAt(peg$currPos) === 34) {
+ s2 = peg$c78;
+ peg$currPos++;
+ } else {
+ s2 = null;
+ if (peg$silentFails === 0) { peg$fail(peg$c79); }
+ }
+ if (s2 === null) {
+ if (input.charCodeAt(peg$currPos) === 92) {
+ s2 = peg$c81;
+ peg$currPos++;
} else {
- r3 = null;
- if (reportFailures === 0) {
- matchFailed("\"\\\"\"");
- }
+ s2 = null;
+ if (peg$silentFails === 0) { peg$fail(peg$c82); }
}
- if (r3 === null) {
- if (input.charCodeAt(pos) === 92) {
- r3 = "\\";
- pos++;
- } else {
- r3 = null;
- if (reportFailures === 0) {
- matchFailed("\"\\\\\"");
- }
- }
- if (r3 === null) {
- r3 = parse_eolChar();
- }
+ if (s2 === null) {
+ s2 = peg$parseeolChar();
}
- reportFailures--;
- if (r3 === null) {
- r3 = "";
+ }
+ peg$silentFails--;
+ if (s2 === null) {
+ s1 = peg$c1;
+ } else {
+ peg$currPos = s1;
+ s1 = peg$c0;
+ }
+ if (s1 !== null) {
+ if (input.length > peg$currPos) {
+ s2 = input.charAt(peg$currPos);
+ peg$currPos++;
} else {
- r3 = null;
- pos = r4;
+ s2 = null;
+ if (peg$silentFails === 0) { peg$fail(peg$c83); }
}
- if (r3 !== null) {
- if (input.length > pos) {
- r4 = input.charAt(pos);
- pos++;
- } else {
- r4 = null;
- if (reportFailures === 0) {
- matchFailed("any character");
- }
- }
- if (r4 !== null) {
- r0 = [r3, r4];
+ if (s2 !== null) {
+ peg$reportedPos = s0;
+ s1 = peg$c84(s2);
+ if (s1 === null) {
+ peg$currPos = s0;
+ s0 = s1;
} else {
- r0 = null;
- pos = r2;
+ s0 = s1;
}
} else {
- r0 = null;
- pos = r2;
- }
- if (r0 !== null) {
- reportedPos = r1;
- r0 = (function(char_) { return char_; })(r4);
- }
- if (r0 === null) {
- pos = r1;
+ peg$currPos = s0;
+ s0 = peg$c0;
}
- return r0;
+ } else {
+ peg$currPos = s0;
+ s0 = peg$c0;
}
-
- function parse_singleQuotedString() {
- var r0, r1, r2, r3, r4, r5;
-
- r1 = pos;
- r2 = pos;
- if (input.charCodeAt(pos) === 39) {
- r3 = "'";
- pos++;
- } else {
- r3 = null;
- if (reportFailures === 0) {
- matchFailed("\"'\"");
- }
- }
- if (r3 !== null) {
- r4 = [];
- r5 = parse_singleQuotedCharacter();
- while (r5 !== null) {
- r4.push(r5);
- r5 = parse_singleQuotedCharacter();
- }
- if (r4 !== null) {
- if (input.charCodeAt(pos) === 39) {
- r5 = "'";
- pos++;
- } else {
- r5 = null;
- if (reportFailures === 0) {
- matchFailed("\"'\"");
- }
- }
- if (r5 !== null) {
- r0 = [r3, r4, r5];
+
+ return s0;
+ }
+
+ function peg$parsesingleQuotedString() {
+ var s0, s1, s2, s3;
+
+ s0 = peg$currPos;
+ if (input.charCodeAt(peg$currPos) === 39) {
+ s1 = peg$c85;
+ peg$currPos++;
+ } else {
+ s1 = null;
+ if (peg$silentFails === 0) { peg$fail(peg$c86); }
+ }
+ if (s1 !== null) {
+ s2 = [];
+ s3 = peg$parsesingleQuotedCharacter();
+ while (s3 !== null) {
+ s2.push(s3);
+ s3 = peg$parsesingleQuotedCharacter();
+ }
+ if (s2 !== null) {
+ if (input.charCodeAt(peg$currPos) === 39) {
+ s3 = peg$c85;
+ peg$currPos++;
+ } else {
+ s3 = null;
+ if (peg$silentFails === 0) { peg$fail(peg$c86); }
+ }
+ if (s3 !== null) {
+ peg$reportedPos = s0;
+ s1 = peg$c80(s2);
+ if (s1 === null) {
+ peg$currPos = s0;
+ s0 = s1;
} else {
- r0 = null;
- pos = r2;
+ s0 = s1;
}
} else {
- r0 = null;
- pos = r2;
- }
- } else {
- r0 = null;
- pos = r2;
- }
- if (r0 !== null) {
- reportedPos = r1;
- r0 = (function(chars) { return chars.join(""); })(r4);
- }
- if (r0 === null) {
- pos = r1;
- }
- return r0;
- }
-
- function parse_singleQuotedCharacter() {
- var r0;
-
- r0 = parse_simpleSingleQuotedCharacter();
- if (r0 === null) {
- r0 = parse_simpleEscapeSequence();
- if (r0 === null) {
- r0 = parse_zeroEscapeSequence();
- if (r0 === null) {
- r0 = parse_hexEscapeSequence();
- if (r0 === null) {
- r0 = parse_unicodeEscapeSequence();
- if (r0 === null) {
- r0 = parse_eolEscapeSequence();
- }
+ peg$currPos = s0;
+ s0 = peg$c0;
+ }
+ } else {
+ peg$currPos = s0;
+ s0 = peg$c0;
+ }
+ } else {
+ peg$currPos = s0;
+ s0 = peg$c0;
+ }
+
+ return s0;
+ }
+
+ function peg$parsesingleQuotedCharacter() {
+ var s0;
+
+ s0 = peg$parsesimpleSingleQuotedCharacter();
+ if (s0 === null) {
+ s0 = peg$parsesimpleEscapeSequence();
+ if (s0 === null) {
+ s0 = peg$parsezeroEscapeSequence();
+ if (s0 === null) {
+ s0 = peg$parsehexEscapeSequence();
+ if (s0 === null) {
+ s0 = peg$parseunicodeEscapeSequence();
+ if (s0 === null) {
+ s0 = peg$parseeolEscapeSequence();
}
}
}
}
- return r0;
}
-
- function parse_simpleSingleQuotedCharacter() {
- var r0, r1, r2, r3, r4;
-
- r1 = pos;
- r2 = pos;
- r4 = pos;
- reportFailures++;
- if (input.charCodeAt(pos) === 39) {
- r3 = "'";
- pos++;
+
+ return s0;
+ }
+
+ function peg$parsesimpleSingleQuotedCharacter() {
+ var s0, s1, s2;
+
+ s0 = peg$currPos;
+ s1 = peg$currPos;
+ peg$silentFails++;
+ if (input.charCodeAt(peg$currPos) === 39) {
+ s2 = peg$c85;
+ peg$currPos++;
+ } else {
+ s2 = null;
+ if (peg$silentFails === 0) { peg$fail(peg$c86); }
+ }
+ if (s2 === null) {
+ if (input.charCodeAt(peg$currPos) === 92) {
+ s2 = peg$c81;
+ peg$currPos++;
} else {
- r3 = null;
- if (reportFailures === 0) {
- matchFailed("\"'\"");
- }
+ s2 = null;
+ if (peg$silentFails === 0) { peg$fail(peg$c82); }
}
- if (r3 === null) {
- if (input.charCodeAt(pos) === 92) {
- r3 = "\\";
- pos++;
- } else {
- r3 = null;
- if (reportFailures === 0) {
- matchFailed("\"\\\\\"");
- }
- }
- if (r3 === null) {
- r3 = parse_eolChar();
- }
+ if (s2 === null) {
+ s2 = peg$parseeolChar();
}
- reportFailures--;
- if (r3 === null) {
- r3 = "";
+ }
+ peg$silentFails--;
+ if (s2 === null) {
+ s1 = peg$c1;
+ } else {
+ peg$currPos = s1;
+ s1 = peg$c0;
+ }
+ if (s1 !== null) {
+ if (input.length > peg$currPos) {
+ s2 = input.charAt(peg$currPos);
+ peg$currPos++;
} else {
- r3 = null;
- pos = r4;
- }
- if (r3 !== null) {
- if (input.length > pos) {
- r4 = input.charAt(pos);
- pos++;
- } else {
- r4 = null;
- if (reportFailures === 0) {
- matchFailed("any character");
- }
- }
- if (r4 !== null) {
- r0 = [r3, r4];
+ s2 = null;
+ if (peg$silentFails === 0) { peg$fail(peg$c83); }
+ }
+ if (s2 !== null) {
+ peg$reportedPos = s0;
+ s1 = peg$c84(s2);
+ if (s1 === null) {
+ peg$currPos = s0;
+ s0 = s1;
} else {
- r0 = null;
- pos = r2;
+ s0 = s1;
}
} else {
- r0 = null;
- pos = r2;
- }
- if (r0 !== null) {
- reportedPos = r1;
- r0 = (function(char_) { return char_; })(r4);
+ peg$currPos = s0;
+ s0 = peg$c0;
}
- if (r0 === null) {
- pos = r1;
- }
- return r0;
+ } else {
+ peg$currPos = s0;
+ s0 = peg$c0;
}
-
- function parse_class() {
- var r0, r1, r2, r3, r4, r5, r6, r7, r8;
-
- reportFailures++;
- r1 = pos;
- r2 = pos;
- if (input.charCodeAt(pos) === 91) {
- r3 = "[";
- pos++;
+
+ return s0;
+ }
+
+ function peg$parseclass() {
+ var s0, s1, s2, s3, s4, s5, s6;
+
+ peg$silentFails++;
+ s0 = peg$currPos;
+ if (input.charCodeAt(peg$currPos) === 91) {
+ s1 = peg$c88;
+ peg$currPos++;
+ } else {
+ s1 = null;
+ if (peg$silentFails === 0) { peg$fail(peg$c89); }
+ }
+ if (s1 !== null) {
+ if (input.charCodeAt(peg$currPos) === 94) {
+ s2 = peg$c90;
+ peg$currPos++;
} else {
- r3 = null;
- if (reportFailures === 0) {
- matchFailed("\"[\"");
- }
+ s2 = null;
+ if (peg$silentFails === 0) { peg$fail(peg$c91); }
}
- if (r3 !== null) {
- if (input.charCodeAt(pos) === 94) {
- r4 = "^";
- pos++;
- } else {
- r4 = null;
- if (reportFailures === 0) {
- matchFailed("\"^\"");
- }
+ if (s2 === null) {
+ s2 = peg$c1;
+ }
+ if (s2 !== null) {
+ s3 = [];
+ s4 = peg$parseclassCharacterRange();
+ if (s4 === null) {
+ s4 = peg$parseclassCharacter();
}
- r4 = r4 !== null ? r4 : "";
- if (r4 !== null) {
- r5 = [];
- r6 = parse_classCharacterRange();
- if (r6 === null) {
- r6 = parse_classCharacter();
+ while (s4 !== null) {
+ s3.push(s4);
+ s4 = peg$parseclassCharacterRange();
+ if (s4 === null) {
+ s4 = peg$parseclassCharacter();
}
- while (r6 !== null) {
- r5.push(r6);
- r6 = parse_classCharacterRange();
- if (r6 === null) {
- r6 = parse_classCharacter();
- }
+ }
+ if (s3 !== null) {
+ if (input.charCodeAt(peg$currPos) === 93) {
+ s4 = peg$c92;
+ peg$currPos++;
+ } else {
+ s4 = null;
+ if (peg$silentFails === 0) { peg$fail(peg$c93); }
}
- if (r5 !== null) {
- if (input.charCodeAt(pos) === 93) {
- r6 = "]";
- pos++;
+ if (s4 !== null) {
+ if (input.charCodeAt(peg$currPos) === 105) {
+ s5 = peg$c73;
+ peg$currPos++;
} else {
- r6 = null;
- if (reportFailures === 0) {
- matchFailed("\"]\"");
- }
+ s5 = null;
+ if (peg$silentFails === 0) { peg$fail(peg$c74); }
}
- if (r6 !== null) {
- if (input.charCodeAt(pos) === 105) {
- r7 = "i";
- pos++;
- } else {
- r7 = null;
- if (reportFailures === 0) {
- matchFailed("\"i\"");
- }
- }
- r7 = r7 !== null ? r7 : "";
- if (r7 !== null) {
- r8 = parse___();
- if (r8 !== null) {
- r0 = [r3, r4, r5, r6, r7, r8];
+ if (s5 === null) {
+ s5 = peg$c1;
+ }
+ if (s5 !== null) {
+ s6 = peg$parse__();
+ if (s6 !== null) {
+ peg$reportedPos = s0;
+ s1 = peg$c94(s2,s3,s5);
+ if (s1 === null) {
+ peg$currPos = s0;
+ s0 = s1;
} else {
- r0 = null;
- pos = r2;
+ s0 = s1;
}
} else {
- r0 = null;
- pos = r2;
+ peg$currPos = s0;
+ s0 = peg$c0;
}
} else {
- r0 = null;
- pos = r2;
+ peg$currPos = s0;
+ s0 = peg$c0;
}
} else {
- r0 = null;
- pos = r2;
+ peg$currPos = s0;
+ s0 = peg$c0;
}
} else {
- r0 = null;
- pos = r2;
+ peg$currPos = s0;
+ s0 = peg$c0;
}
} else {
- r0 = null;
- pos = r2;
+ peg$currPos = s0;
+ s0 = peg$c0;
}
- if (r0 !== null) {
- reportedPos = r1;
- r0 = (function(inverted, parts, flags) {
- var partsConverted = utils.map(parts, function(part) { return part.data; });
- var rawText = "["
- + inverted
- + utils.map(parts, function(part) { return part.rawText; }).join("")
- + "]"
- + flags;
-
- return {
- type: "class",
- parts: partsConverted,
- // FIXME: Get the raw text from the input directly.
- rawText: rawText,
- inverted: inverted === "^",
- ignoreCase: flags === "i"
- };
- })(r4, r5, r7);
- }
- if (r0 === null) {
- pos = r1;
- }
- reportFailures--;
- if (reportFailures === 0 && r0 === null) {
- matchFailed("character class");
- }
- return r0;
- }
-
- function parse_classCharacterRange() {
- var r0, r1, r2, r3, r4, r5;
-
- r1 = pos;
- r2 = pos;
- r3 = parse_classCharacter();
- if (r3 !== null) {
- if (input.charCodeAt(pos) === 45) {
- r4 = "-";
- pos++;
- } else {
- r4 = null;
- if (reportFailures === 0) {
- matchFailed("\"-\"");
- }
- }
- if (r4 !== null) {
- r5 = parse_classCharacter();
- if (r5 !== null) {
- r0 = [r3, r4, r5];
+ } else {
+ peg$currPos = s0;
+ s0 = peg$c0;
+ }
+ peg$silentFails--;
+ if (s0 === null) {
+ s1 = null;
+ if (peg$silentFails === 0) { peg$fail(peg$c87); }
+ }
+
+ return s0;
+ }
+
+ function peg$parseclassCharacterRange() {
+ var s0, s1, s2, s3;
+
+ s0 = peg$currPos;
+ s1 = peg$parseclassCharacter();
+ if (s1 !== null) {
+ if (input.charCodeAt(peg$currPos) === 45) {
+ s2 = peg$c95;
+ peg$currPos++;
+ } else {
+ s2 = null;
+ if (peg$silentFails === 0) { peg$fail(peg$c96); }
+ }
+ if (s2 !== null) {
+ s3 = peg$parseclassCharacter();
+ if (s3 !== null) {
+ peg$reportedPos = s0;
+ s1 = peg$c97(s1,s3);
+ if (s1 === null) {
+ peg$currPos = s0;
+ s0 = s1;
} else {
- r0 = null;
- pos = r2;
+ s0 = s1;
}
} else {
- r0 = null;
- pos = r2;
+ peg$currPos = s0;
+ s0 = peg$c0;
}
} else {
- r0 = null;
- pos = r2;
+ peg$currPos = s0;
+ s0 = peg$c0;
}
- if (r0 !== null) {
- reportedPos = r1;
- r0 = (function(begin, end) {
- if (begin.data.charCodeAt(0) > end.data.charCodeAt(0)) {
- throw new this.SyntaxError(
- "Invalid character range: " + begin.rawText + "-" + end.rawText + "."
- );
- }
-
- return {
- data: [begin.data, end.data],
- // FIXME: Get the raw text from the input directly.
- rawText: begin.rawText + "-" + end.rawText
- };
- })(r3, r5);
- }
- if (r0 === null) {
- pos = r1;
- }
- return r0;
- }
-
- function parse_classCharacter() {
- var r0, r1;
-
- r1 = pos;
- r0 = parse_bracketDelimitedCharacter();
- if (r0 !== null) {
- reportedPos = r1;
- r0 = (function(char_) {
- return {
- data: char_,
- // FIXME: Get the raw text from the input directly.
- rawText: utils.quoteForRegexpClass(char_)
- };
- })(r0);
- }
- if (r0 === null) {
- pos = r1;
- }
- return r0;
- }
-
- function parse_bracketDelimitedCharacter() {
- var r0;
-
- r0 = parse_simpleBracketDelimitedCharacter();
- if (r0 === null) {
- r0 = parse_simpleEscapeSequence();
- if (r0 === null) {
- r0 = parse_zeroEscapeSequence();
- if (r0 === null) {
- r0 = parse_hexEscapeSequence();
- if (r0 === null) {
- r0 = parse_unicodeEscapeSequence();
- if (r0 === null) {
- r0 = parse_eolEscapeSequence();
- }
+ } else {
+ peg$currPos = s0;
+ s0 = peg$c0;
+ }
+
+ return s0;
+ }
+
+ function peg$parseclassCharacter() {
+ var s0, s1;
+
+ s0 = peg$currPos;
+ s1 = peg$parsebracketDelimitedCharacter();
+ if (s1 !== null) {
+ peg$reportedPos = s0;
+ s1 = peg$c98(s1);
+ }
+ if (s1 === null) {
+ peg$currPos = s0;
+ s0 = s1;
+ } else {
+ s0 = s1;
+ }
+
+ return s0;
+ }
+
+ function peg$parsebracketDelimitedCharacter() {
+ var s0;
+
+ s0 = peg$parsesimpleBracketDelimitedCharacter();
+ if (s0 === null) {
+ s0 = peg$parsesimpleEscapeSequence();
+ if (s0 === null) {
+ s0 = peg$parsezeroEscapeSequence();
+ if (s0 === null) {
+ s0 = peg$parsehexEscapeSequence();
+ if (s0 === null) {
+ s0 = peg$parseunicodeEscapeSequence();
+ if (s0 === null) {
+ s0 = peg$parseeolEscapeSequence();
}
}
}
}
- return r0;
}
-
- function parse_simpleBracketDelimitedCharacter() {
- var r0, r1, r2, r3, r4;
-
- r1 = pos;
- r2 = pos;
- r4 = pos;
- reportFailures++;
- if (input.charCodeAt(pos) === 93) {
- r3 = "]";
- pos++;
+
+ return s0;
+ }
+
+ function peg$parsesimpleBracketDelimitedCharacter() {
+ var s0, s1, s2;
+
+ s0 = peg$currPos;
+ s1 = peg$currPos;
+ peg$silentFails++;
+ if (input.charCodeAt(peg$currPos) === 93) {
+ s2 = peg$c92;
+ peg$currPos++;
+ } else {
+ s2 = null;
+ if (peg$silentFails === 0) { peg$fail(peg$c93); }
+ }
+ if (s2 === null) {
+ if (input.charCodeAt(peg$currPos) === 92) {
+ s2 = peg$c81;
+ peg$currPos++;
} else {
- r3 = null;
- if (reportFailures === 0) {
- matchFailed("\"]\"");
- }
+ s2 = null;
+ if (peg$silentFails === 0) { peg$fail(peg$c82); }
}
- if (r3 === null) {
- if (input.charCodeAt(pos) === 92) {
- r3 = "\\";
- pos++;
- } else {
- r3 = null;
- if (reportFailures === 0) {
- matchFailed("\"\\\\\"");
- }
- }
- if (r3 === null) {
- r3 = parse_eolChar();
- }
+ if (s2 === null) {
+ s2 = peg$parseeolChar();
}
- reportFailures--;
- if (r3 === null) {
- r3 = "";
+ }
+ peg$silentFails--;
+ if (s2 === null) {
+ s1 = peg$c1;
+ } else {
+ peg$currPos = s1;
+ s1 = peg$c0;
+ }
+ if (s1 !== null) {
+ if (input.length > peg$currPos) {
+ s2 = input.charAt(peg$currPos);
+ peg$currPos++;
} else {
- r3 = null;
- pos = r4;
+ s2 = null;
+ if (peg$silentFails === 0) { peg$fail(peg$c83); }
}
- if (r3 !== null) {
- if (input.length > pos) {
- r4 = input.charAt(pos);
- pos++;
+ if (s2 !== null) {
+ peg$reportedPos = s0;
+ s1 = peg$c84(s2);
+ if (s1 === null) {
+ peg$currPos = s0;
+ s0 = s1;
} else {
- r4 = null;
- if (reportFailures === 0) {
- matchFailed("any character");
- }
- }
- if (r4 !== null) {
- r0 = [r3, r4];
- } else {
- r0 = null;
- pos = r2;
+ s0 = s1;
}
} else {
- r0 = null;
- pos = r2;
- }
- if (r0 !== null) {
- reportedPos = r1;
- r0 = (function(char_) { return char_; })(r4);
+ peg$currPos = s0;
+ s0 = peg$c0;
}
- if (r0 === null) {
- pos = r1;
- }
- return r0;
+ } else {
+ peg$currPos = s0;
+ s0 = peg$c0;
}
-
- function parse_simpleEscapeSequence() {
- var r0, r1, r2, r3, r4, r5;
-
- r1 = pos;
- r2 = pos;
- if (input.charCodeAt(pos) === 92) {
- r3 = "\\";
- pos++;
- } else {
- r3 = null;
- if (reportFailures === 0) {
- matchFailed("\"\\\\\"");
- }
- }
- if (r3 !== null) {
- r5 = pos;
- reportFailures++;
- r4 = parse_digit();
- if (r4 === null) {
- if (input.charCodeAt(pos) === 120) {
- r4 = "x";
- pos++;
+
+ return s0;
+ }
+
+ function peg$parsesimpleEscapeSequence() {
+ var s0, s1, s2, s3;
+
+ s0 = peg$currPos;
+ if (input.charCodeAt(peg$currPos) === 92) {
+ s1 = peg$c81;
+ peg$currPos++;
+ } else {
+ s1 = null;
+ if (peg$silentFails === 0) { peg$fail(peg$c82); }
+ }
+ if (s1 !== null) {
+ s2 = peg$currPos;
+ peg$silentFails++;
+ s3 = peg$parsedigit();
+ if (s3 === null) {
+ if (input.charCodeAt(peg$currPos) === 120) {
+ s3 = peg$c99;
+ peg$currPos++;
+ } else {
+ s3 = null;
+ if (peg$silentFails === 0) { peg$fail(peg$c100); }
+ }
+ if (s3 === null) {
+ if (input.charCodeAt(peg$currPos) === 117) {
+ s3 = peg$c101;
+ peg$currPos++;
} else {
- r4 = null;
- if (reportFailures === 0) {
- matchFailed("\"x\"");
- }
+ s3 = null;
+ if (peg$silentFails === 0) { peg$fail(peg$c102); }
}
- if (r4 === null) {
- if (input.charCodeAt(pos) === 117) {
- r4 = "u";
- pos++;
- } else {
- r4 = null;
- if (reportFailures === 0) {
- matchFailed("\"u\"");
- }
- }
- if (r4 === null) {
- r4 = parse_eolChar();
- }
+ if (s3 === null) {
+ s3 = peg$parseeolChar();
}
}
- reportFailures--;
- if (r4 === null) {
- r4 = "";
+ }
+ peg$silentFails--;
+ if (s3 === null) {
+ s2 = peg$c1;
+ } else {
+ peg$currPos = s2;
+ s2 = peg$c0;
+ }
+ if (s2 !== null) {
+ if (input.length > peg$currPos) {
+ s3 = input.charAt(peg$currPos);
+ peg$currPos++;
} else {
- r4 = null;
- pos = r5;
+ s3 = null;
+ if (peg$silentFails === 0) { peg$fail(peg$c83); }
}
- if (r4 !== null) {
- if (input.length > pos) {
- r5 = input.charAt(pos);
- pos++;
- } else {
- r5 = null;
- if (reportFailures === 0) {
- matchFailed("any character");
- }
- }
- if (r5 !== null) {
- r0 = [r3, r4, r5];
+ if (s3 !== null) {
+ peg$reportedPos = s0;
+ s1 = peg$c103(s3);
+ if (s1 === null) {
+ peg$currPos = s0;
+ s0 = s1;
} else {
- r0 = null;
- pos = r2;
+ s0 = s1;
}
} else {
- r0 = null;
- pos = r2;
+ peg$currPos = s0;
+ s0 = peg$c0;
}
} else {
- r0 = null;
- pos = r2;
- }
- if (r0 !== null) {
- reportedPos = r1;
- r0 = (function(char_) {
- return char_
- .replace("b", "\b")
- .replace("f", "\f")
- .replace("n", "\n")
- .replace("r", "\r")
- .replace("t", "\t")
- .replace("v", "\x0B"); // IE does not recognize "\v".
- })(r5);
+ peg$currPos = s0;
+ s0 = peg$c0;
}
- if (r0 === null) {
- pos = r1;
- }
- return r0;
+ } else {
+ peg$currPos = s0;
+ s0 = peg$c0;
}
-
- function parse_zeroEscapeSequence() {
- var r0, r1, r2, r3, r4, r5;
-
- r1 = pos;
- r2 = pos;
- if (input.substr(pos, 2) === "\\0") {
- r3 = "\\0";
- pos += 2;
+
+ return s0;
+ }
+
+ function peg$parsezeroEscapeSequence() {
+ var s0, s1, s2, s3;
+
+ s0 = peg$currPos;
+ if (input.substr(peg$currPos, 2) === peg$c104) {
+ s1 = peg$c104;
+ peg$currPos += 2;
+ } else {
+ s1 = null;
+ if (peg$silentFails === 0) { peg$fail(peg$c105); }
+ }
+ if (s1 !== null) {
+ s2 = peg$currPos;
+ peg$silentFails++;
+ s3 = peg$parsedigit();
+ peg$silentFails--;
+ if (s3 === null) {
+ s2 = peg$c1;
} else {
- r3 = null;
- if (reportFailures === 0) {
- matchFailed("\"\\\\0\"");
- }
+ peg$currPos = s2;
+ s2 = peg$c0;
}
- if (r3 !== null) {
- r5 = pos;
- reportFailures++;
- r4 = parse_digit();
- reportFailures--;
- if (r4 === null) {
- r4 = "";
+ if (s2 !== null) {
+ peg$reportedPos = s0;
+ s1 = peg$c106();
+ if (s1 === null) {
+ peg$currPos = s0;
+ s0 = s1;
} else {
- r4 = null;
- pos = r5;
- }
- if (r4 !== null) {
- r0 = [r3, r4];
- } else {
- r0 = null;
- pos = r2;
+ s0 = s1;
}
} else {
- r0 = null;
- pos = r2;
- }
- if (r0 !== null) {
- reportedPos = r1;
- r0 = (function() { return "\x00"; })();
- }
- if (r0 === null) {
- pos = r1;
+ peg$currPos = s0;
+ s0 = peg$c0;
}
- return r0;
+ } else {
+ peg$currPos = s0;
+ s0 = peg$c0;
}
-
- function parse_hexEscapeSequence() {
- var r0, r1, r2, r3, r4, r5, r6, r7, r8;
-
- r1 = pos;
- r2 = pos;
- if (input.substr(pos, 2) === "\\x") {
- r3 = "\\x";
- pos += 2;
- } else {
- r3 = null;
- if (reportFailures === 0) {
- matchFailed("\"\\\\x\"");
- }
- }
- if (r3 !== null) {
- r5 = pos;
- r6 = pos;
- r7 = parse_hexDigit();
- if (r7 !== null) {
- r8 = parse_hexDigit();
- if (r8 !== null) {
- r4 = [r7, r8];
- } else {
- r4 = null;
- pos = r6;
- }
+
+ return s0;
+ }
+
+ function peg$parsehexEscapeSequence() {
+ var s0, s1, s2, s3, s4, s5;
+
+ s0 = peg$currPos;
+ if (input.substr(peg$currPos, 2) === peg$c107) {
+ s1 = peg$c107;
+ peg$currPos += 2;
+ } else {
+ s1 = null;
+ if (peg$silentFails === 0) { peg$fail(peg$c108); }
+ }
+ if (s1 !== null) {
+ s2 = peg$currPos;
+ s3 = peg$currPos;
+ s4 = peg$parsehexDigit();
+ if (s4 !== null) {
+ s5 = peg$parsehexDigit();
+ if (s5 !== null) {
+ s4 = [s4, s5];
+ s3 = s4;
} else {
- r4 = null;
- pos = r6;
- }
- if (r4 !== null) {
- r4 = input.substring(pos, r5);
+ peg$currPos = s3;
+ s3 = peg$c0;
}
- if (r4 !== null) {
- r0 = [r3, r4];
+ } else {
+ peg$currPos = s3;
+ s3 = peg$c0;
+ }
+ if (s3 !== null) {
+ s3 = input.substring(s2, peg$currPos);
+ }
+ s2 = s3;
+ if (s2 !== null) {
+ peg$reportedPos = s0;
+ s1 = peg$c109(s2);
+ if (s1 === null) {
+ peg$currPos = s0;
+ s0 = s1;
} else {
- r0 = null;
- pos = r2;
+ s0 = s1;
}
} else {
- r0 = null;
- pos = r2;
+ peg$currPos = s0;
+ s0 = peg$c0;
}
- if (r0 !== null) {
- reportedPos = r1;
- r0 = (function(digits) {
- return String.fromCharCode(parseInt(digits, 16));
- })(r4);
- }
- if (r0 === null) {
- pos = r1;
- }
- return r0;
- }
-
- function parse_unicodeEscapeSequence() {
- var r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10;
-
- r1 = pos;
- r2 = pos;
- if (input.substr(pos, 2) === "\\u") {
- r3 = "\\u";
- pos += 2;
- } else {
- r3 = null;
- if (reportFailures === 0) {
- matchFailed("\"\\\\u\"");
- }
- }
- if (r3 !== null) {
- r5 = pos;
- r6 = pos;
- r7 = parse_hexDigit();
- if (r7 !== null) {
- r8 = parse_hexDigit();
- if (r8 !== null) {
- r9 = parse_hexDigit();
- if (r9 !== null) {
- r10 = parse_hexDigit();
- if (r10 !== null) {
- r4 = [r7, r8, r9, r10];
- } else {
- r4 = null;
- pos = r6;
- }
+ } else {
+ peg$currPos = s0;
+ s0 = peg$c0;
+ }
+
+ return s0;
+ }
+
+ function peg$parseunicodeEscapeSequence() {
+ var s0, s1, s2, s3, s4, s5, s6, s7;
+
+ s0 = peg$currPos;
+ if (input.substr(peg$currPos, 2) === peg$c110) {
+ s1 = peg$c110;
+ peg$currPos += 2;
+ } else {
+ s1 = null;
+ if (peg$silentFails === 0) { peg$fail(peg$c111); }
+ }
+ if (s1 !== null) {
+ s2 = peg$currPos;
+ s3 = peg$currPos;
+ s4 = peg$parsehexDigit();
+ if (s4 !== null) {
+ s5 = peg$parsehexDigit();
+ if (s5 !== null) {
+ s6 = peg$parsehexDigit();
+ if (s6 !== null) {
+ s7 = peg$parsehexDigit();
+ if (s7 !== null) {
+ s4 = [s4, s5, s6, s7];
+ s3 = s4;
} else {
- r4 = null;
- pos = r6;
+ peg$currPos = s3;
+ s3 = peg$c0;
}
} else {
- r4 = null;
- pos = r6;
+ peg$currPos = s3;
+ s3 = peg$c0;
}
} else {
- r4 = null;
- pos = r6;
- }
- if (r4 !== null) {
- r4 = input.substring(pos, r5);
- }
- if (r4 !== null) {
- r0 = [r3, r4];
- } else {
- r0 = null;
- pos = r2;
+ peg$currPos = s3;
+ s3 = peg$c0;
}
} else {
- r0 = null;
- pos = r2;
- }
- if (r0 !== null) {
- reportedPos = r1;
- r0 = (function(digits) {
- return String.fromCharCode(parseInt(digits, 16));
- })(r4);
- }
- if (r0 === null) {
- pos = r1;
+ peg$currPos = s3;
+ s3 = peg$c0;
}
- return r0;
- }
-
- function parse_eolEscapeSequence() {
- var r0, r1, r2, r3, r4;
-
- r1 = pos;
- r2 = pos;
- if (input.charCodeAt(pos) === 92) {
- r3 = "\\";
- pos++;
- } else {
- r3 = null;
- if (reportFailures === 0) {
- matchFailed("\"\\\\\"");
- }
+ if (s3 !== null) {
+ s3 = input.substring(s2, peg$currPos);
}
- if (r3 !== null) {
- r4 = parse_eol();
- if (r4 !== null) {
- r0 = [r3, r4];
+ s2 = s3;
+ if (s2 !== null) {
+ peg$reportedPos = s0;
+ s1 = peg$c109(s2);
+ if (s1 === null) {
+ peg$currPos = s0;
+ s0 = s1;
} else {
- r0 = null;
- pos = r2;
+ s0 = s1;
}
} else {
- r0 = null;
- pos = r2;
- }
- if (r0 !== null) {
- reportedPos = r1;
- r0 = (function(eol) { return eol; })(r4);
+ peg$currPos = s0;
+ s0 = peg$c0;
}
- if (r0 === null) {
- pos = r1;
- }
- return r0;
+ } else {
+ peg$currPos = s0;
+ s0 = peg$c0;
}
-
- function parse_digit() {
- var r0;
-
- if (/^[0-9]/.test(input.charAt(pos))) {
- r0 = input.charAt(pos);
- pos++;
- } else {
- r0 = null;
- if (reportFailures === 0) {
- matchFailed("[0-9]");
- }
- }
- return r0;
+
+ return s0;
+ }
+
+ function peg$parseeolEscapeSequence() {
+ var s0, s1, s2;
+
+ s0 = peg$currPos;
+ if (input.charCodeAt(peg$currPos) === 92) {
+ s1 = peg$c81;
+ peg$currPos++;
+ } else {
+ s1 = null;
+ if (peg$silentFails === 0) { peg$fail(peg$c82); }
}
-
- function parse_hexDigit() {
- var r0;
-
- if (/^[0-9a-fA-F]/.test(input.charAt(pos))) {
- r0 = input.charAt(pos);
- pos++;
- } else {
- r0 = null;
- if (reportFailures === 0) {
- matchFailed("[0-9a-fA-F]");
+ if (s1 !== null) {
+ s2 = peg$parseeol();
+ if (s2 !== null) {
+ peg$reportedPos = s0;
+ s1 = peg$c112(s2);
+ if (s1 === null) {
+ peg$currPos = s0;
+ s0 = s1;
+ } else {
+ s0 = s1;
}
+ } else {
+ peg$currPos = s0;
+ s0 = peg$c0;
}
- return r0;
+ } else {
+ peg$currPos = s0;
+ s0 = peg$c0;
}
-
- function parse_letter() {
- var r0;
-
- r0 = parse_lowerCaseLetter();
- if (r0 === null) {
- r0 = parse_upperCaseLetter();
- }
- return r0;
+
+ return s0;
+ }
+
+ function peg$parsedigit() {
+ var s0;
+
+ if (peg$c113.test(input.charAt(peg$currPos))) {
+ s0 = input.charAt(peg$currPos);
+ peg$currPos++;
+ } else {
+ s0 = null;
+ if (peg$silentFails === 0) { peg$fail(peg$c114); }
}
-
- function parse_lowerCaseLetter() {
- var r0;
-
- if (/^[a-z]/.test(input.charAt(pos))) {
- r0 = input.charAt(pos);
- pos++;
- } else {
- r0 = null;
- if (reportFailures === 0) {
- matchFailed("[a-z]");
- }
- }
- return r0;
+
+ return s0;
+ }
+
+ function peg$parsehexDigit() {
+ var s0;
+
+ if (peg$c115.test(input.charAt(peg$currPos))) {
+ s0 = input.charAt(peg$currPos);
+ peg$currPos++;
+ } else {
+ s0 = null;
+ if (peg$silentFails === 0) { peg$fail(peg$c116); }
}
-
- function parse_upperCaseLetter() {
- var r0;
-
- if (/^[A-Z]/.test(input.charAt(pos))) {
- r0 = input.charAt(pos);
- pos++;
- } else {
- r0 = null;
- if (reportFailures === 0) {
- matchFailed("[A-Z]");
- }
- }
- return r0;
+
+ return s0;
+ }
+
+ function peg$parseletter() {
+ var s0;
+
+ s0 = peg$parselowerCaseLetter();
+ if (s0 === null) {
+ s0 = peg$parseupperCaseLetter();
+ }
+
+ return s0;
+ }
+
+ function peg$parselowerCaseLetter() {
+ var s0;
+
+ if (peg$c117.test(input.charAt(peg$currPos))) {
+ s0 = input.charAt(peg$currPos);
+ peg$currPos++;
+ } else {
+ s0 = null;
+ if (peg$silentFails === 0) { peg$fail(peg$c118); }
}
-
- function parse___() {
- var r0, r1;
-
- r0 = [];
- r1 = parse_whitespace();
- if (r1 === null) {
- r1 = parse_eol();
- if (r1 === null) {
- r1 = parse_comment();
- }
- }
- while (r1 !== null) {
- r0.push(r1);
- r1 = parse_whitespace();
- if (r1 === null) {
- r1 = parse_eol();
- if (r1 === null) {
- r1 = parse_comment();
- }
- }
- }
- return r0;
- }
-
- function parse_comment() {
- var r0;
-
- reportFailures++;
- r0 = parse_singleLineComment();
- if (r0 === null) {
- r0 = parse_multiLineComment();
- }
- reportFailures--;
- if (reportFailures === 0 && r0 === null) {
- matchFailed("comment");
- }
- return r0;
- }
-
- function parse_singleLineComment() {
- var r0, r1, r2, r3, r4, r5, r6, r7;
-
- r1 = pos;
- if (input.substr(pos, 2) === "//") {
- r2 = "//";
- pos += 2;
- } else {
- r2 = null;
- if (reportFailures === 0) {
- matchFailed("\"//\"");
- }
- }
- if (r2 !== null) {
- r3 = [];
- r5 = pos;
- r7 = pos;
- reportFailures++;
- r6 = parse_eolChar();
- reportFailures--;
- if (r6 === null) {
- r6 = "";
- } else {
- r6 = null;
- pos = r7;
- }
- if (r6 !== null) {
- if (input.length > pos) {
- r7 = input.charAt(pos);
- pos++;
- } else {
- r7 = null;
- if (reportFailures === 0) {
- matchFailed("any character");
- }
- }
- if (r7 !== null) {
- r4 = [r6, r7];
- } else {
- r4 = null;
- pos = r5;
- }
- } else {
- r4 = null;
- pos = r5;
- }
- while (r4 !== null) {
- r3.push(r4);
- r5 = pos;
- r7 = pos;
- reportFailures++;
- r6 = parse_eolChar();
- reportFailures--;
- if (r6 === null) {
- r6 = "";
+
+ return s0;
+ }
+
+ function peg$parseupperCaseLetter() {
+ var s0;
+
+ if (peg$c119.test(input.charAt(peg$currPos))) {
+ s0 = input.charAt(peg$currPos);
+ peg$currPos++;
+ } else {
+ s0 = null;
+ if (peg$silentFails === 0) { peg$fail(peg$c120); }
+ }
+
+ return s0;
+ }
+
+ function peg$parse__() {
+ var s0, s1;
+
+ s0 = [];
+ s1 = peg$parsewhitespace();
+ if (s1 === null) {
+ s1 = peg$parseeol();
+ if (s1 === null) {
+ s1 = peg$parsecomment();
+ }
+ }
+ while (s1 !== null) {
+ s0.push(s1);
+ s1 = peg$parsewhitespace();
+ if (s1 === null) {
+ s1 = peg$parseeol();
+ if (s1 === null) {
+ s1 = peg$parsecomment();
+ }
+ }
+ }
+
+ return s0;
+ }
+
+ function peg$parsecomment() {
+ var s0, s1;
+
+ peg$silentFails++;
+ s0 = peg$parsesingleLineComment();
+ if (s0 === null) {
+ s0 = peg$parsemultiLineComment();
+ }
+ peg$silentFails--;
+ if (s0 === null) {
+ s1 = null;
+ if (peg$silentFails === 0) { peg$fail(peg$c121); }
+ }
+
+ return s0;
+ }
+
+ function peg$parsesingleLineComment() {
+ var s0, s1, s2, s3, s4, s5;
+
+ s0 = peg$currPos;
+ if (input.substr(peg$currPos, 2) === peg$c122) {
+ s1 = peg$c122;
+ peg$currPos += 2;
+ } else {
+ s1 = null;
+ if (peg$silentFails === 0) { peg$fail(peg$c123); }
+ }
+ if (s1 !== null) {
+ s2 = [];
+ s3 = peg$currPos;
+ s4 = peg$currPos;
+ peg$silentFails++;
+ s5 = peg$parseeolChar();
+ peg$silentFails--;
+ if (s5 === null) {
+ s4 = peg$c1;
+ } else {
+ peg$currPos = s4;
+ s4 = peg$c0;
+ }
+ if (s4 !== null) {
+ if (input.length > peg$currPos) {
+ s5 = input.charAt(peg$currPos);
+ peg$currPos++;
+ } else {
+ s5 = null;
+ if (peg$silentFails === 0) { peg$fail(peg$c83); }
+ }
+ if (s5 !== null) {
+ s4 = [s4, s5];
+ s3 = s4;
+ } else {
+ peg$currPos = s3;
+ s3 = peg$c0;
+ }
+ } else {
+ peg$currPos = s3;
+ s3 = peg$c0;
+ }
+ while (s3 !== null) {
+ s2.push(s3);
+ s3 = peg$currPos;
+ s4 = peg$currPos;
+ peg$silentFails++;
+ s5 = peg$parseeolChar();
+ peg$silentFails--;
+ if (s5 === null) {
+ s4 = peg$c1;
+ } else {
+ peg$currPos = s4;
+ s4 = peg$c0;
+ }
+ if (s4 !== null) {
+ if (input.length > peg$currPos) {
+ s5 = input.charAt(peg$currPos);
+ peg$currPos++;
} else {
- r6 = null;
- pos = r7;
+ s5 = null;
+ if (peg$silentFails === 0) { peg$fail(peg$c83); }
}
- if (r6 !== null) {
- if (input.length > pos) {
- r7 = input.charAt(pos);
- pos++;
- } else {
- r7 = null;
- if (reportFailures === 0) {
- matchFailed("any character");
- }
- }
- if (r7 !== null) {
- r4 = [r6, r7];
- } else {
- r4 = null;
- pos = r5;
- }
+ if (s5 !== null) {
+ s4 = [s4, s5];
+ s3 = s4;
} else {
- r4 = null;
- pos = r5;
+ peg$currPos = s3;
+ s3 = peg$c0;
}
- }
- if (r3 !== null) {
- r0 = [r2, r3];
} else {
- r0 = null;
- pos = r1;
+ peg$currPos = s3;
+ s3 = peg$c0;
}
- } else {
- r0 = null;
- pos = r1;
}
- return r0;
- }
-
- function parse_multiLineComment() {
- var r0, r1, r2, r3, r4, r5, r6, r7;
-
- r1 = pos;
- if (input.substr(pos, 2) === "/*") {
- r2 = "/*";
- pos += 2;
+ if (s2 !== null) {
+ s1 = [s1, s2];
+ s0 = s1;
} else {
- r2 = null;
- if (reportFailures === 0) {
- matchFailed("\"/*\"");
- }
+ peg$currPos = s0;
+ s0 = peg$c0;
}
- if (r2 !== null) {
- r3 = [];
- r5 = pos;
- r7 = pos;
- reportFailures++;
- if (input.substr(pos, 2) === "*/") {
- r6 = "*/";
- pos += 2;
- } else {
- r6 = null;
- if (reportFailures === 0) {
- matchFailed("\"*/\"");
- }
- }
- reportFailures--;
- if (r6 === null) {
- r6 = "";
- } else {
- r6 = null;
- pos = r7;
- }
- if (r6 !== null) {
- if (input.length > pos) {
- r7 = input.charAt(pos);
- pos++;
+ } else {
+ peg$currPos = s0;
+ s0 = peg$c0;
+ }
+
+ return s0;
+ }
+
+ function peg$parsemultiLineComment() {
+ var s0, s1, s2, s3, s4, s5;
+
+ s0 = peg$currPos;
+ if (input.substr(peg$currPos, 2) === peg$c124) {
+ s1 = peg$c124;
+ peg$currPos += 2;
+ } else {
+ s1 = null;
+ if (peg$silentFails === 0) { peg$fail(peg$c125); }
+ }
+ if (s1 !== null) {
+ s2 = [];
+ s3 = peg$currPos;
+ s4 = peg$currPos;
+ peg$silentFails++;
+ if (input.substr(peg$currPos, 2) === peg$c126) {
+ s5 = peg$c126;
+ peg$currPos += 2;
+ } else {
+ s5 = null;
+ if (peg$silentFails === 0) { peg$fail(peg$c127); }
+ }
+ peg$silentFails--;
+ if (s5 === null) {
+ s4 = peg$c1;
+ } else {
+ peg$currPos = s4;
+ s4 = peg$c0;
+ }
+ if (s4 !== null) {
+ if (input.length > peg$currPos) {
+ s5 = input.charAt(peg$currPos);
+ peg$currPos++;
+ } else {
+ s5 = null;
+ if (peg$silentFails === 0) { peg$fail(peg$c83); }
+ }
+ if (s5 !== null) {
+ s4 = [s4, s5];
+ s3 = s4;
+ } else {
+ peg$currPos = s3;
+ s3 = peg$c0;
+ }
+ } else {
+ peg$currPos = s3;
+ s3 = peg$c0;
+ }
+ while (s3 !== null) {
+ s2.push(s3);
+ s3 = peg$currPos;
+ s4 = peg$currPos;
+ peg$silentFails++;
+ if (input.substr(peg$currPos, 2) === peg$c126) {
+ s5 = peg$c126;
+ peg$currPos += 2;
+ } else {
+ s5 = null;
+ if (peg$silentFails === 0) { peg$fail(peg$c127); }
+ }
+ peg$silentFails--;
+ if (s5 === null) {
+ s4 = peg$c1;
+ } else {
+ peg$currPos = s4;
+ s4 = peg$c0;
+ }
+ if (s4 !== null) {
+ if (input.length > peg$currPos) {
+ s5 = input.charAt(peg$currPos);
+ peg$currPos++;
} else {
- r7 = null;
- if (reportFailures === 0) {
- matchFailed("any character");
- }
+ s5 = null;
+ if (peg$silentFails === 0) { peg$fail(peg$c83); }
}
- if (r7 !== null) {
- r4 = [r6, r7];
+ if (s5 !== null) {
+ s4 = [s4, s5];
+ s3 = s4;
} else {
- r4 = null;
- pos = r5;
+ peg$currPos = s3;
+ s3 = peg$c0;
}
} else {
- r4 = null;
- pos = r5;
- }
- while (r4 !== null) {
- r3.push(r4);
- r5 = pos;
- r7 = pos;
- reportFailures++;
- if (input.substr(pos, 2) === "*/") {
- r6 = "*/";
- pos += 2;
- } else {
- r6 = null;
- if (reportFailures === 0) {
- matchFailed("\"*/\"");
- }
- }
- reportFailures--;
- if (r6 === null) {
- r6 = "";
- } else {
- r6 = null;
- pos = r7;
- }
- if (r6 !== null) {
- if (input.length > pos) {
- r7 = input.charAt(pos);
- pos++;
- } else {
- r7 = null;
- if (reportFailures === 0) {
- matchFailed("any character");
- }
- }
- if (r7 !== null) {
- r4 = [r6, r7];
- } else {
- r4 = null;
- pos = r5;
- }
- } else {
- r4 = null;
- pos = r5;
- }
+ peg$currPos = s3;
+ s3 = peg$c0;
}
- if (r3 !== null) {
- if (input.substr(pos, 2) === "*/") {
- r4 = "*/";
- pos += 2;
- } else {
- r4 = null;
- if (reportFailures === 0) {
- matchFailed("\"*/\"");
- }
- }
- if (r4 !== null) {
- r0 = [r2, r3, r4];
- } else {
- r0 = null;
- pos = r1;
- }
+ }
+ if (s2 !== null) {
+ if (input.substr(peg$currPos, 2) === peg$c126) {
+ s3 = peg$c126;
+ peg$currPos += 2;
+ } else {
+ s3 = null;
+ if (peg$silentFails === 0) { peg$fail(peg$c127); }
+ }
+ if (s3 !== null) {
+ s1 = [s1, s2, s3];
+ s0 = s1;
} else {
- r0 = null;
- pos = r1;
+ peg$currPos = s0;
+ s0 = peg$c0;
}
} else {
- r0 = null;
- pos = r1;
+ peg$currPos = s0;
+ s0 = peg$c0;
}
- return r0;
+ } else {
+ peg$currPos = s0;
+ s0 = peg$c0;
+ }
+
+ return s0;
+ }
+
+ function peg$parseeol() {
+ var s0, s1;
+
+ peg$silentFails++;
+ if (input.charCodeAt(peg$currPos) === 10) {
+ s0 = peg$c129;
+ peg$currPos++;
+ } else {
+ s0 = null;
+ if (peg$silentFails === 0) { peg$fail(peg$c130); }
}
-
- function parse_eol() {
- var r0;
-
- reportFailures++;
- if (input.charCodeAt(pos) === 10) {
- r0 = "\n";
- pos++;
+ if (s0 === null) {
+ if (input.substr(peg$currPos, 2) === peg$c131) {
+ s0 = peg$c131;
+ peg$currPos += 2;
} else {
- r0 = null;
- if (reportFailures === 0) {
- matchFailed("\"\\n\"");
- }
+ s0 = null;
+ if (peg$silentFails === 0) { peg$fail(peg$c132); }
}
- if (r0 === null) {
- if (input.substr(pos, 2) === "\r\n") {
- r0 = "\r\n";
- pos += 2;
+ if (s0 === null) {
+ if (input.charCodeAt(peg$currPos) === 13) {
+ s0 = peg$c133;
+ peg$currPos++;
} else {
- r0 = null;
- if (reportFailures === 0) {
- matchFailed("\"\\r\\n\"");
- }
+ s0 = null;
+ if (peg$silentFails === 0) { peg$fail(peg$c134); }
}
- if (r0 === null) {
- if (input.charCodeAt(pos) === 13) {
- r0 = "\r";
- pos++;
+ if (s0 === null) {
+ if (input.charCodeAt(peg$currPos) === 8232) {
+ s0 = peg$c135;
+ peg$currPos++;
} else {
- r0 = null;
- if (reportFailures === 0) {
- matchFailed("\"\\r\"");
- }
+ s0 = null;
+ if (peg$silentFails === 0) { peg$fail(peg$c136); }
}
- if (r0 === null) {
- if (input.charCodeAt(pos) === 8232) {
- r0 = "\u2028";
- pos++;
+ if (s0 === null) {
+ if (input.charCodeAt(peg$currPos) === 8233) {
+ s0 = peg$c137;
+ peg$currPos++;
} else {
- r0 = null;
- if (reportFailures === 0) {
- matchFailed("\"\\u2028\"");
- }
- }
- if (r0 === null) {
- if (input.charCodeAt(pos) === 8233) {
- r0 = "\u2029";
- pos++;
- } else {
- r0 = null;
- if (reportFailures === 0) {
- matchFailed("\"\\u2029\"");
- }
- }
+ s0 = null;
+ if (peg$silentFails === 0) { peg$fail(peg$c138); }
}
}
}
}
- reportFailures--;
- if (reportFailures === 0 && r0 === null) {
- matchFailed("end of line");
- }
- return r0;
- }
-
- function parse_eolChar() {
- var r0;
-
- if (/^[\n\r\u2028\u2029]/.test(input.charAt(pos))) {
- r0 = input.charAt(pos);
- pos++;
- } else {
- r0 = null;
- if (reportFailures === 0) {
- matchFailed("[\\n\\r\\u2028\\u2029]");
- }
- }
- return r0;
- }
-
- function parse_whitespace() {
- var r0;
-
- reportFailures++;
- if (/^[ \t\x0B\f\xA0\uFEFF\u1680\u180E\u2000-\u200A\u202F\u205F\u3000]/.test(input.charAt(pos))) {
- r0 = input.charAt(pos);
- pos++;
- } else {
- r0 = null;
- if (reportFailures === 0) {
- matchFailed("[ \\t\\x0B\\f\\xA0\\uFEFF\\u1680\\u180E\\u2000-\\u200A\\u202F\\u205F\\u3000]");
- }
- }
- reportFailures--;
- if (reportFailures === 0 && r0 === null) {
- matchFailed("whitespace");
- }
- return r0;
- }
-
-
- function cleanupExpected(expected) {
- expected.sort();
-
- var lastExpected = null;
- var cleanExpected = [];
- for (var i = 0; i < expected.length; i++) {
- if (expected[i] !== lastExpected) {
- cleanExpected.push(expected[i]);
- lastExpected = expected[i];
- }
- }
- return cleanExpected;
- }
-
-
- var utils = require("./utils");
-
-
- 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) {
- reportedPos = Math.max(pos, rightmostFailuresPos);
- var found = reportedPos < input.length ? input.charAt(reportedPos) : null;
- var reportedPosDetails = computeReportedPosDetails();
-
- throw new this.SyntaxError(
- cleanupExpected(rightmostFailuresExpected),
- found,
- reportedPos,
- reportedPosDetails.line,
- reportedPosDetails.column
- );
- }
-
- return result;
+ }
+ peg$silentFails--;
+ if (s0 === null) {
+ s1 = null;
+ if (peg$silentFails === 0) { peg$fail(peg$c128); }
+ }
+
+ return s0;
}
- };
-
- /* Thrown when a parser encounters a syntax error. */
-
- result.SyntaxError = function(expected, found, offset, line, column) {
- function buildMessage(expected, found) {
- var expectedHumanized, foundHumanized;
-
- switch (expected.length) {
- case 0:
- expectedHumanized = "end of input";
- break;
- case 1:
- expectedHumanized = expected[0];
- break;
- default:
- expectedHumanized = expected.slice(0, expected.length - 1).join(", ")
- + " or "
- + expected[expected.length - 1];
+
+ function peg$parseeolChar() {
+ var s0;
+
+ if (peg$c139.test(input.charAt(peg$currPos))) {
+ s0 = input.charAt(peg$currPos);
+ peg$currPos++;
+ } else {
+ s0 = null;
+ if (peg$silentFails === 0) { peg$fail(peg$c140); }
}
-
- foundHumanized = found ? quote(found) : "end of input";
-
- return "Expected " + expectedHumanized + " but " + foundHumanized + " found.";
+
+ return s0;
}
-
- this.name = "SyntaxError";
- this.expected = expected;
- this.found = found;
- this.message = buildMessage(expected, found);
- this.offset = offset;
- this.line = line;
- this.column = column;
+
+ function peg$parsewhitespace() {
+ var s0, s1;
+
+ peg$silentFails++;
+ if (peg$c142.test(input.charAt(peg$currPos))) {
+ s0 = input.charAt(peg$currPos);
+ peg$currPos++;
+ } else {
+ s0 = null;
+ if (peg$silentFails === 0) { peg$fail(peg$c143); }
+ }
+ peg$silentFails--;
+ if (s0 === null) {
+ s1 = null;
+ if (peg$silentFails === 0) { peg$fail(peg$c141); }
+ }
+
+ return s0;
+ }
+
+
+ var utils = require("./utils");
+
+
+ peg$result = peg$startRuleFunction();
+
+ if (peg$result !== null && peg$currPos === input.length) {
+ return peg$result;
+ } else {
+ peg$cleanupExpected(peg$maxFailExpected);
+ peg$reportedPos = Math.max(peg$currPos, peg$maxFailPos);
+
+ throw new SyntaxError(
+ peg$maxFailExpected,
+ peg$reportedPos < input.length ? input.charAt(peg$reportedPos) : null,
+ peg$reportedPos,
+ peg$computePosDetails(peg$reportedPos).line,
+ peg$computePosDetails(peg$reportedPos).column
+ );
+ }
+ }
+
+ return {
+ SyntaxError: SyntaxError,
+ parse : parse
};
-
- subclass(result.SyntaxError, Error);
-
- return result;
})();
diff --git a/lib/utils.js b/lib/utils.js
index 18018f4..cf6aacc 100644
--- a/lib/utils.js
+++ b/lib/utils.js
@@ -22,6 +22,16 @@ var utils = {
}
},
+ indexOf: function(array, callback) {
+ var length = array.length;
+ for (var i = 0; i < length; i++) {
+ if (callback(array[i])) {
+ return i;
+ }
+ }
+ return -1;
+ },
+
contains: function(array, value) {
/*
* Stupid IE does not have Array.prototype.indexOf, otherwise this function
@@ -209,6 +219,10 @@ var utils = {
findRuleByName: function(ast, name) {
return utils.find(ast.rules, function(r) { return r.name === name; });
+ },
+
+ indexOfRuleByName: function(ast, name) {
+ return utils.indexOf(ast.rules, function(r) { return r.name === name; });
}
};
diff --git a/package.json b/package.json
index c3e5523..bdd7a42 100644
--- a/package.json
+++ b/package.json
@@ -19,9 +19,10 @@
"examples/javascript.pegjs",
"examples/json.pegjs",
"lib/compiler.js",
+ "lib/compiler/opcodes.js",
"lib/compiler/passes.js",
- "lib/compiler/passes/allocate-registers.js",
- "lib/compiler/passes/generate-code.js",
+ "lib/compiler/passes/generate-bytecode.js",
+ "lib/compiler/passes/generate-javascript.js",
"lib/compiler/passes/remove-proxy-rules.js",
"lib/compiler/passes/report-left-recursion.js",
"lib/compiler/passes/report-missing-rules.js",
diff --git a/spec/compiler/passes/allocate-registers.spec.js b/spec/compiler/passes/allocate-registers.spec.js
deleted file mode 100644
index 3e31621..0000000
--- a/spec/compiler/passes/allocate-registers.spec.js
+++ /dev/null
@@ -1,309 +0,0 @@
-describe("compiler pass |allocateRegisters|", function() {
- var pass = PEG.compiler.passes.allocateRegisters;
-
- function ruleDetails(details) { return { rules: [details] }; }
-
- function expressionDetails(details) {
- return ruleDetails({ expression: details });
- }
-
- function innerExpressionDetails(details) {
- return expressionDetails({ expression: details });
- }
-
- var reuseResultDetails = innerExpressionDetails({ resultIndex: 0 }),
- allocResultDetails = innerExpressionDetails({ resultIndex: 1 }),
- savePosDetails = expressionDetails({ posIndex: 1 }),
- scopedDetails = expressionDetails({ params: {} }),
- blockedDetails = expressionDetails({
- elements: [
- {},
- {
- resultIndex: 3,
- posIndex: 5,
- elements: [{ resultIndex: 6 }, { resultIndex: 7 }]
- }
- ]
- }),
- unblockedDetails = expressionDetails({
- elements: [
- {},
- {
- resultIndex: 3,
- posIndex: 4,
- elements: [{ resultIndex: 5 }, { resultIndex: 6 }]
- }
- ]
- });
-
- describe("for rule", function() {
- it("allocates a new result register for the expression", function() {
- expect(pass).toChangeAST('start = "a"', expressionDetails({
- resultIndex: 0
- }));
- });
-
- it("counts used registers", function() {
- expect(pass).toChangeAST('start = "a"', ruleDetails({
- registerCount: 1
- }));
- expect(pass).toChangeAST('start = "a"*', ruleDetails({
- registerCount: 2
- }));
- expect(pass).toChangeAST('start = ("a"*)*', ruleDetails({
- registerCount: 3
- }));
- });
-
- it("resets used registers counter", function() {
- expect(pass).toChangeAST('a = "a"*; b = "b"', {
- rules: [ { registerCount: 2 }, { registerCount: 1 }]
- });
- });
- });
-
- describe("for named", function() {
- it("reuses its own result register for the expression", function() {
- expect(pass).toChangeAST('start "start" = "a"', reuseResultDetails);
- });
- });
-
- describe("for choice", function() {
- it("reuses its own result register for the alternatives", function() {
- expect(pass).toChangeAST('start = "a" / "b" / "c"', expressionDetails({
- alternatives: [
- { resultIndex: 0 },
- { resultIndex: 0 },
- { resultIndex: 0 }
- ]
- }));
- });
-
- it("creates a new scope", function() {
- expect(pass).toChangeAST('start = (a:"a" / "b" / "c") { }', scopedDetails);
- });
-
- it("unblocks registers blocked by its children", function() {
- expect(pass).toChangeAST(
- 'start = ((a:"a" / "b" / "c") "d") ("e" "f")',
- unblockedDetails
- );
- });
- });
-
- describe("for action", function() {
- it("allocates a position register", function() {
- expect(pass).toChangeAST('start = "a" { }', savePosDetails);
- });
-
- it("reuses its own result register for the expression", function() {
- expect(pass).toChangeAST('start = "a" { }', reuseResultDetails);
- });
-
- it("creates a new scope", function() {
- expect(pass).toChangeAST('start = (a:"a" { }) { }', scopedDetails);
- });
-
- it("unblocks registers blocked by its children", function() {
- expect(pass).toChangeAST(
- 'start = ((a:"a" { }) "b") ("c" "d")',
- unblockedDetails
- );
- });
-
- it("computes params", function() {
- expect(pass).toChangeAST('start = a:"a" b:"b" c:"c" { }', expressionDetails({
- params: { a: 3, b: 4, c: 5 }
- }));
- });
- });
-
- describe("for sequence", function() {
- it("allocates a position register", function() {
- expect(pass).toChangeAST('start = ', savePosDetails);
- expect(pass).toChangeAST('start = "a" "b" "c"', savePosDetails);
- });
-
- it("allocates new result registers for the elements", function() {
- expect(pass).toChangeAST('start = "a" "b" "c"', expressionDetails({
- elements: [{ resultIndex: 2 }, { resultIndex: 3 }, { resultIndex: 4 }]
- }));
- });
-
- it("does not create a new scope", function() {
- expect(pass).toChangeAST(
- 'start = a:"a" b:"b" c:"c" { }',
- expressionDetails({ params: { a: 3, b: 4, c: 5 } })
- );
- });
-
- it("does not unblock blocked result registers from children", function() {
- expect(pass).toChangeAST(
- 'start = (a:"a" "b") ("c" "d")',
- blockedDetails
- );
- });
- });
-
- describe("for labeled", function() {
- it("reuses its own result register for the expression", function() {
- expect(pass).toChangeAST('start = a:"a"', reuseResultDetails);
- });
-
- it("creates a new scope", function() {
- expect(pass).toChangeAST('start = a:(b:"b") { }', expressionDetails({
- params: { a: 0 }
- }));
- });
-
- it("unblocks registers blocked by its children", function() {
- expect(pass).toChangeAST(
- 'start = (a:(b:"b") "c") ("d" "e")',
- blockedDetails
- );
- });
-
- it("adds label to the environment", function() {
- expect(pass).toChangeAST('start = a:"a" { }', expressionDetails({
- params: { a: 0 }
- }));
- });
-
- it("blocks its own result register", function() {
- expect(pass).toChangeAST(
- 'start = (a:"a" "b") ("c" "d")',
- blockedDetails
- );
- });
- });
-
- describe("for text", function() {
- it("allocates a position register", function() {
- expect(pass).toChangeAST('start = $"a"', savePosDetails);
- });
-
- it("reuses its own result register for the expression", function() {
- expect(pass).toChangeAST('start = $"a"', reuseResultDetails);
- });
-
- it("creates a new scope", function() {
- expect(pass).toChangeAST('start = $(a:"a") { }', scopedDetails);
- });
-
- it("unblocks registers blocked by its children", function() {
- expect(pass).toChangeAST(
- 'start = ($(a:"a") "b") ("c" "d")',
- unblockedDetails
- );
- });
- });
-
- describe("for simple and", function() {
- it("allocates a position register", function() {
- expect(pass).toChangeAST('start = &"a"', savePosDetails);
- });
-
- it("reuses its own result register for the expression", function() {
- expect(pass).toChangeAST('start = &"a"', reuseResultDetails);
- });
-
- it("creates a new scope", function() {
- expect(pass).toChangeAST('start = &(a:"a") { }', scopedDetails);
- });
-
- it("unblocks registers blocked by its children", function() {
- expect(pass).toChangeAST(
- 'start = (&(a:"a") "b") ("c" "d")',
- unblockedDetails
- );
- });
- });
-
- describe("for simple not", function() {
- it("allocates a position register", function() {
- expect(pass).toChangeAST('start = !"a"', savePosDetails);
- });
-
- it("reuses its own result register for the expression", function() {
- expect(pass).toChangeAST('start = !"a"', reuseResultDetails);
- });
-
- it("creates a new scope", function() {
- expect(pass).toChangeAST('start = !(a:"a") { }', scopedDetails);
- });
-
- it("unblocks registers blocked by its children", function() {
- expect(pass).toChangeAST(
- 'start = (!(a:"a") "b") ("c" "d")',
- unblockedDetails
- );
- });
- });
-
- describe("for semantic and", function() {
- it("computes params", function() {
- expect(pass).toChangeAST('start = a:"a" b:"b" c:"c" &{ }', expressionDetails({
- elements: [{}, {}, {}, { params: { a: 2, b: 3, c: 4 } }]
- }));
- });
- });
-
- describe("for semantic not", function() {
- it("computes params", function() {
- expect(pass).toChangeAST('start = a:"a" b:"b" c:"c" !{ }', expressionDetails({
- elements: [{}, {}, {}, { params: { a: 2, b: 3, c: 4 } }]
- }));
- });
- });
-
- describe("for optional", function() {
- it("reuses its own result register for the expression", function() {
- expect(pass).toChangeAST('start = "a"?', reuseResultDetails);
- });
-
- it("creates a new scope", function() {
- expect(pass).toChangeAST('start = (a:"a")? { }', scopedDetails);
- });
-
- it("unblocks registers blocked by its children", function() {
- expect(pass).toChangeAST(
- 'start = ((a:"a")? "b") ("c" "d")',
- unblockedDetails
- );
- });
- });
-
- describe("for zero or more", function() {
- it("allocates a new result register for the expression", function() {
- expect(pass).toChangeAST('start = "a"*', allocResultDetails);
- });
-
- it("creates a new scope", function() {
- expect(pass).toChangeAST('start = (a:"a")* { }', scopedDetails);
- });
-
- it("unblocks registers blocked by its children", function() {
- expect(pass).toChangeAST(
- 'start = ((a:"a")* "b") ("c" "d")',
- unblockedDetails
- );
- });
- });
-
- describe("for one or more", function() {
- it("allocates a new result register for the expression", function() {
- expect(pass).toChangeAST('start = "a"+', allocResultDetails);
- });
-
- it("creates a new scope", function() {
- expect(pass).toChangeAST('start = (a:"a")+ { }', scopedDetails);
- });
-
- it("unblocks registers blocked by its children", function() {
- expect(pass).toChangeAST(
- 'start = ((a:"a")+ "b") ("c" "d")',
- unblockedDetails
- );
- });
- });
-});
diff --git a/spec/compiler/passes/generate-bytecode.spec.js b/spec/compiler/passes/generate-bytecode.spec.js
new file mode 100644
index 0000000..8b58dec
--- /dev/null
+++ b/spec/compiler/passes/generate-bytecode.spec.js
@@ -0,0 +1,674 @@
+describe("compiler pass |generateBytecode|", function() {
+ var pass = PEG.compiler.passes.generateBytecode;
+
+ function bytecodeDetails(bytecode) {
+ return {
+ rules: [{ bytecode: bytecode }]
+ };
+ }
+
+ function constsDetails(consts) { return { consts: consts }; }
+
+ describe("for grammar", function() {
+ it("generates correct bytecode", function() {
+ expect(pass).toChangeAST([
+ 'a = "a"',
+ 'b = "b"',
+ 'c = "c"'
+ ].join("\n"), {
+ rules: [
+ { bytecode: [15, 0, 2, 2, 19, 0, 20, 1] },
+ { bytecode: [15, 2, 2, 2, 19, 2, 20, 3] },
+ { bytecode: [15, 4, 2, 2, 19, 4, 20, 5] }
+ ]
+ });
+ });
+
+ it("defines correct constants", function() {
+ expect(pass).toChangeAST([
+ 'a = "a"',
+ 'b = "b"',
+ 'c = "c"'
+ ].join("\n"), constsDetails([
+ '"a"',
+ '"\\"a\\""',
+ '"b"',
+ '"\\"b\\""',
+ '"c"',
+ '"\\"c\\""'
+ ]));
+ });
+ });
+
+ describe("for rule", function() {
+ it("generates correct bytecode", function() {
+ expect(pass).toChangeAST('start = "a"', bytecodeDetails([
+ 15, 0, 2, 2, 19, 0, 20, 1 //
+ ]));
+ });
+ });
+
+ describe("for named", function() {
+ var grammar = 'start "start" = "a"';
+ it("generates correct bytecode", function() {
+ expect(pass).toChangeAST(grammar, bytecodeDetails([
+ 25, // SILENT_FAILS_ON
+ 15, 1, 2, 2, 19, 1, 20, 2, //
+ 26, // SILENT_FAILS_OFF
+ 11, 2, 0, // IF_ERROR
+ 20, 0 // FAIL
+ ]));
+ });
+
+ it("defines correct constants", function() {
+ expect(pass).toChangeAST(
+ grammar,
+ constsDetails(['"start"', '"a"', '"\\"a\\""'])
+ );
+ });
+ });
+
+ describe("for choice", function() {
+ it("generates correct bytecode", function() {
+ expect(pass).toChangeAST('start = "a" / "b" / "c"', bytecodeDetails([
+ 15, 0, 2, 2, 19, 0, 20, 1, //
+ 11, 21, 0, // IF_ERROR
+ 2, // * POP
+ 15, 2, 2, 2, 19, 2, 20, 3, //
+ 11, 9, 0, // IF_ERROR
+ 2, // * POP
+ 15, 4, 2, 2, 19, 4, 20, 5 //
+ ]));
+ });
+ });
+
+ describe("for action", function() {
+ describe("without labels", function() {
+ var grammar = 'start = { code }';
+
+ it("generates correct bytecode", function() {
+ expect(pass).toChangeAST(grammar, bytecodeDetails([
+ 1, // PUSH_CURR_POS
+ 0, 0, // PUSH
+ 12, 6, 0, // IF_NOT_ERROR
+ 21, 1, // * REPORT_SAVED_POS
+ 23, 1, 1, 0, // CALL
+ 11, 1, 1, // IF_ERROR
+ 6, // * NIP_CURR_POS
+ 5 // * NIP
+ ]));
+ });
+
+ it("defines correct constants", function() {
+ expect(pass).toChangeAST(
+ grammar,
+ constsDetails(['[]', 'function() { code }'])
+ );
+ });
+ });
+
+ describe("with one label", function() {
+ var grammar = 'start = a:"a" { code }';
+
+ it("generates correct bytecode", function() {
+ expect(pass).toChangeAST(grammar, bytecodeDetails([
+ 1, // PUSH_CURR_POS
+ 15, 0, 2, 2, 19, 0, 20, 1, //
+ 12, 7, 0, // IF_NOT_ERROR
+ 21, 1, // * REPORT_SAVED_POS
+ 23, 2, 1, 1, 0, // CALL
+ 11, 1, 1, // IF_ERROR
+ 6, // * NIP_CURR_POS
+ 5 // * NIP
+ ]));
+ });
+
+ it("defines correct constants", function() {
+ expect(pass).toChangeAST(
+ grammar,
+ constsDetails(['"a"', '"\\"a\\""', 'function(a) { code }'])
+ );
+ });
+ });
+
+ describe("with multiple labels", function() {
+ var grammar = 'start = a:"a" b:"b" c:"c" { code }';
+ it("generates correct bytecode", function() {
+ expect(pass).toChangeAST(grammar, bytecodeDetails([
+ 1, // PUSH_CURR_POS
+ 15, 1, 2, 2, 19, 1, 20, 2, //
+ 12, 46, 4, // IF_NOT_ERROR
+ 15, 3, 2, 2, 19, 3, 20, 4, // *
+ 12, 30, 5, // IF_NOT_ERROR
+ 15, 5, 2, 2, 19, 5, 20, 6, // *
+ 12, 14, 5, // IF_NOT_ERROR
+ 21, 3, // * REPORT_SAVED_POS
+ 23, 7, 3, 3, 2, 1, 0, // CALL
+ 11, 1, 1, // IF_ERROR
+ 6, // * NIP_CURR_POS
+ 5, // * NIP
+ 4, 3, // * POP_N
+ 3, // POP_CURR_POS
+ 0, 0, // PUSH
+ 4, 2, // * POP_N
+ 3, // POP_CURR_POS
+ 0, 0, // PUSH
+ 2, // * POP
+ 3, // POP_CURR_POS
+ 0, 0 // PUSH
+ ]));
+ });
+
+ it("defines correct constants", function() {
+ expect(pass).toChangeAST(grammar, constsDetails([
+ 'null',
+ '"a"',
+ '"\\"a\\""',
+ '"b"',
+ '"\\"b\\""',
+ '"c"',
+ '"\\"c\\""',
+ 'function(a, b, c) { code }'
+ ]));
+ });
+ });
+ });
+
+ describe("for sequence", function() {
+ describe("empty", function() {
+ var grammar = 'start = ';
+
+ it("generates correct bytecode", function() {
+ expect(pass).toChangeAST(grammar, bytecodeDetails([
+ 0, 0 // PUSH
+ ]));
+ });
+
+ it("defines correct constants", function() {
+ expect(pass).toChangeAST(grammar, constsDetails(['[]']));
+ });
+ });
+
+ describe("non-empty", function() {
+ var grammar = 'start = "a" "b" "c"';
+
+ it("generates correct bytecode", function() {
+ expect(pass).toChangeAST(grammar, bytecodeDetails([
+ 1, // PUSH_CURR_POS
+ 15, 1, 2, 2, 19, 1, 20, 2, //
+ 12, 35, 4, // IF_NOT_ERROR
+ 15, 3, 2, 2, 19, 3, 20, 4, // *
+ 12, 19, 5, // IF_NOT_ERROR
+ 15, 5, 2, 2, 19, 5, 20, 6, // *
+ 12, 3, 5, // IF_NOT_ERROR
+ 8, 3, // * WRAP
+ 5, // NIP
+ 4, 3, // * POP_N
+ 3, // POP_CURR_POS
+ 0, 0, // PUSH
+ 4, 2, // * POP_N
+ 3, // POP_CURR_POS
+ 0, 0, // PUSH
+ 2, // * POP
+ 3, // POP_CURR_POS
+ 0, 0 // PUSH
+ ]));
+ });
+
+ it("defines correct constants", function() {
+ expect(pass).toChangeAST(
+ grammar,
+ constsDetails([
+ 'null',
+ '"a"',
+ '"\\"a\\""',
+ '"b"',
+ '"\\"b\\""',
+ '"c"',
+ '"\\"c\\""'
+ ])
+ );
+ });
+ });
+ });
+
+ describe("for labeled", function() {
+ it("generates correct bytecode", function() {
+ expect(pass).toChangeAST('start = a:"a"', bytecodeDetails([
+ 15, 0, 2, 2, 19, 0, 20, 1 //
+ ]));
+ });
+ });
+
+ describe("for text", function() {
+ it("generates correct bytecode", function() {
+ expect(pass).toChangeAST('start = $"a"', bytecodeDetails([
+ 1, // PUSH_CURR_POS
+ 15, 0, 2, 2, 19, 0, 20, 1, //
+ 12, 1, 0, // IF_NOT_ERROR
+ 9, // * TEXT
+ 5 // NIP
+ ]));
+ });
+ });
+
+ describe("for simple and", function() {
+ var grammar = 'start = &"a"';
+
+ it("generates correct bytecode", function() {
+ expect(pass).toChangeAST(grammar, bytecodeDetails([
+ 1, // PUSH_CURR_POS
+ 25, // SILENT_FAILS_ON
+ 15, 2, 2, 2, 19, 2, 20, 3, //
+ 26, // SILENT_FAILS_OFF
+ 12, 4, 4, // IF_NOT_ERROR
+ 2, // * POP
+ 3, // POP_CURR_POS
+ 0, 0, // PUSH
+ 2, // * POP
+ 2, // POP
+ 0, 1 // PUSH
+ ]));
+ });
+
+ it("defines correct constants", function() {
+ expect(pass).toChangeAST(
+ grammar,
+ constsDetails(['""', 'null', '"a"', '"\\"a\\""'])
+ );
+ });
+ });
+
+ describe("for simple not", function() {
+ var grammar = 'start = !"a"';
+
+ it("generates correct bytecode", function() {
+ expect(pass).toChangeAST(grammar, bytecodeDetails([
+ 1, // PUSH_CURR_POS
+ 25, // SILENT_FAILS_ON
+ 15, 2, 2, 2, 19, 2, 20, 3, //
+ 26, // SILENT_FAILS_OFF
+ 11, 4, 4, // IF_ERROR
+ 2, // * POP
+ 2, // POP
+ 0, 0, // PUSH
+ 2, // * POP
+ 3, // POP_CURR_POS
+ 0, 1 // PUSH
+ ]));
+ });
+
+ it("defines correct constants", function() {
+ expect(pass).toChangeAST(
+ grammar,
+ constsDetails(['""', 'null', '"a"', '"\\"a\\""'])
+ );
+ });
+ });
+
+ describe("for semantic and", function() {
+ describe("without labels", function() {
+ var grammar = 'start = &{ code }';
+
+ it("generates correct bytecode", function() {
+ expect(pass).toChangeAST(grammar, bytecodeDetails([
+ 22, // REPORT_CURR_POS
+ 23, 0, 0, 0, // CALL
+ 10, 3, 3, // IF
+ 2, // * POP
+ 0, 1, // PUSH
+ 2, // * POP
+ 0, 2 // PUSH
+ ]));
+ });
+
+ it("defines correct constants", function() {
+ expect(pass).toChangeAST(
+ grammar,
+ constsDetails(['function() { code }', '""', 'null'])
+ );
+ });
+ });
+
+ describe("with labels", function() {
+ var grammar = 'start = a:"a" b:"b" c:"c" &{ code }';
+
+ it("generates correct bytecode", function() {
+ expect(pass).toChangeAST(grammar, bytecodeDetails([
+ 1, // PUSH_CURR_POS
+ 15, 1, 2, 2, 19, 1, 20, 2, //
+ 12, 60, 4, // IF_NOT_ERROR
+ 15, 3, 2, 2, 19, 3, 20, 4, // *
+ 12, 44, 5, // IF_NOT_ERROR
+ 15, 5, 2, 2, 19, 5, 20, 6, // *
+ 12, 28, 5, // IF_NOT_ERROR
+ 22, // * REPORT_CURR_POS
+ 23, 7, 0, 3, 2, 1, 0, // CALL
+ 10, 3, 3, // IF
+ 2, // * POP
+ 0, 8, // PUSH
+ 2, // * POP
+ 0, 0, // PUSH
+ 12, 3, 5, // IF_NOT_ERROR
+ 8, 4, // * WRAP
+ 5, // NIP
+ 4, 4, // * POP_N
+ 3, // POP_CURR_POS
+ 0, 0, // PUSH
+ 4, 3, // * POP_N
+ 3, // POP_CURR_POS
+ 0, 0, // PUSH
+ 4, 2, // * POP_N
+ 3, // POP_CURR_POS
+ 0, 0, // PUSH
+ 2, // * POP
+ 3, // POP_CURR_POS
+ 0, 0 // PUSH
+ ]));
+ });
+
+ it("defines correct constants", function() {
+ expect(pass).toChangeAST(grammar, constsDetails([
+ 'null',
+ '"a"',
+ '"\\"a\\""',
+ '"b"',
+ '"\\"b\\""',
+ '"c"',
+ '"\\"c\\""',
+ 'function(a, b, c) { code }',
+ '""'
+ ]));
+ });
+ });
+ });
+
+ describe("for semantic not", function() {
+ describe("without labels", function() {
+ var grammar = 'start = !{ code }';
+
+ it("generates correct bytecode", function() {
+ expect(pass).toChangeAST(grammar, bytecodeDetails([
+ 22, // REPORT_CURR_POS
+ 23, 0, 0, 0, // CALL_PREDICATE
+ 10, 3, 3, // IF
+ 2, // * POP
+ 0, 2, // PUSH
+ 2, // * POP
+ 0, 1 // PUSH
+ ]));
+ });
+
+ it("defines correct constants", function() {
+ expect(pass).toChangeAST(
+ grammar,
+ constsDetails(['function() { code }', '""', 'null'])
+ );
+ });
+ });
+
+ describe("with labels", function() {
+ var grammar = 'start = a:"a" b:"b" c:"c" !{ code }';
+
+ it("generates correct bytecode", function() {
+ expect(pass).toChangeAST(grammar, bytecodeDetails([
+ 1, // PUSH_CURR_POS
+ 15, 1, 2, 2, 19, 1, 20, 2, //
+ 12, 60, 4, // IF_NOT_ERROR
+ 15, 3, 2, 2, 19, 3, 20, 4, // *
+ 12, 44, 5, // IF_NOT_ERROR
+ 15, 5, 2, 2, 19, 5, 20, 6, // *
+ 12, 28, 5, // IF_NOT_ERROR
+ 22, // * REPORT_CURR_POS
+ 23, 7, 0, 3, 2, 1, 0, // CALL
+ 10, 3, 3, // IF
+ 2, // * POP
+ 0, 0, // PUSH
+ 2, // * POP
+ 0, 8, // PUSH
+ 12, 3, 5, // IF_NOT_ERROR
+ 8, 4, // * WRAP
+ 5, // NIP
+ 4, 4, // * POP_N
+ 3, // POP_CURR_POS
+ 0, 0, // PUSH
+ 4, 3, // * POP_N
+ 3, // POP_CURR_POS
+ 0, 0, // PUSH
+ 4, 2, // * POP_N
+ 3, // POP_CURR_POS
+ 0, 0, // PUSH
+ 2, // * POP
+ 3, // POP_CURR_POS
+ 0, 0 // PUSH
+ ]));
+ });
+
+ it("defines correct constants", function() {
+ expect(pass).toChangeAST(grammar, constsDetails([
+ 'null',
+ '"a"',
+ '"\\"a\\""',
+ '"b"',
+ '"\\"b\\""',
+ '"c"',
+ '"\\"c\\""',
+ 'function(a, b, c) { code }',
+ '""'
+ ]));
+ });
+ });
+ });
+
+ describe("for optional", function() {
+ var grammar = 'start = "a"?';
+
+ it("generates correct bytecode", function() {
+ expect(pass).toChangeAST(grammar, bytecodeDetails([
+ 15, 1, 2, 2, 19, 1, 20, 2, //
+ 11, 3, 0, // IF_ERROR
+ 2, // * POP
+ 0, 0 // PUSH
+ ]));
+ });
+
+ it("defines correct constants", function() {
+ expect(pass).toChangeAST(
+ grammar,
+ constsDetails(['""', '"a"', '"\\"a\\""'])
+ );
+ });
+ });
+
+ describe("for zero or more", function() {
+ var grammar = 'start = "a"*';
+
+ it("generates correct bytecode", function() {
+ expect(pass).toChangeAST(grammar, bytecodeDetails([
+ 0, 0, // PUSH
+ 15, 1, 2, 2, 19, 1, 20, 2, //
+ 13, 9, // WHILE_NOT_ERROR
+ 7, // * APPEND
+ 15, 1, 2, 2, 19, 1, 20, 2, //
+ 2 // POP
+ ]));
+ });
+
+ it("defines correct constants", function() {
+ expect(pass).toChangeAST(
+ grammar,
+ constsDetails(['[]', '"a"', '"\\"a\\""'])
+ );
+ });
+ });
+
+ describe("for one or more", function() {
+ var grammar = 'start = "a"+';
+
+ it("generates correct bytecode", function() {
+ expect(pass).toChangeAST(grammar, bytecodeDetails([
+ 0, 0, // PUSH
+ 15, 2, 2, 2, 19, 2, 20, 3, //
+ 12, 12, 4, // IF_NOT_ERROR
+ 13, 9, // * WHILE_NOT_ERROR
+ 7, // * APPEND
+ 15, 2, 2, 2, 19, 2, 20, 3, //
+ 2, // POP
+ 2, // * POP
+ 2, // POP
+ 0, 1 // PUSH
+ ]));
+ });
+
+ it("defines correct constants", function() {
+ expect(pass).toChangeAST(
+ grammar,
+ constsDetails(['[]', 'null', '"a"', '"\\"a\\""'])
+ );
+ });
+ });
+
+ describe("for rule reference", function() {
+ it("generates correct bytecode", function() {
+ expect(pass).toChangeAST([
+ 'start = other',
+ 'other = "other"'
+ ].join("\n"), {
+ rules: [
+ {
+ bytecode: [24, 1] // RULE
+ },
+ { }
+ ]
+ });
+ });
+ });
+
+ describe("for literal", function() {
+ describe("empty", function() {
+ var grammar = 'start = ""';
+
+ it("generates correct bytecode", function() {
+ expect(pass).toChangeAST(grammar, bytecodeDetails([
+ 0, 0 // PUSH
+ ]));
+ });
+
+ it("defines correct constants", function() {
+ expect(pass).toChangeAST(grammar, constsDetails(['""']));
+ });
+ });
+
+ describe("non-empty case-sensitive", function() {
+ var grammar = 'start = "a"';
+
+ it("generates correct bytecode", function() {
+ expect(pass).toChangeAST(grammar, bytecodeDetails([
+ 15, 0, 2, 2, // MATCH_STRING
+ 19, 0, // * ACCEPT_STRING
+ 20, 1 // * FAIL
+ ]));
+ });
+
+ it("defines correct constants", function() {
+ expect(pass).toChangeAST(grammar, constsDetails(['"a"', '"\\"a\\""']));
+ });
+ });
+
+ describe("non-empty case-insensitive", function() {
+ var grammar = 'start = "A"i';
+
+ it("generates correct bytecode", function() {
+ expect(pass).toChangeAST(grammar, bytecodeDetails([
+ 16, 0, 2, 2, // MATCH_STRING_IC
+ 18, 1, // * ACCEPT_N
+ 20, 1 // * FAIL
+ ]));
+ });
+
+ it("defines correct constants", function() {
+ expect(pass).toChangeAST(grammar, constsDetails(['"a"', '"\\"A\\""']));
+ });
+ });
+ });
+
+ describe("for class", function() {
+ it("generates correct bytecode", function() {
+ expect(pass).toChangeAST('start = [a]', bytecodeDetails([
+ 17, 0, 2, 2, // MATCH_REGEXP
+ 18, 1, // * ACCEPT_N
+ 20, 1 // * FAIL
+ ]));
+ });
+
+ describe("non-empty non-inverted case-sensitive", function() {
+ it("defines correct constants", function() {
+ expect(pass).toChangeAST(
+ 'start = [a]',
+ constsDetails(['/^[a]/', '"[a]"'])
+ );
+ });
+ });
+
+ describe("non-empty inverted case-sensitive", function() {
+ it("defines correct constants", function() {
+ expect(pass).toChangeAST(
+ 'start = [^a]',
+ constsDetails(['/^[^a]/', '"[^a]"'])
+ );
+ });
+ });
+
+ describe("non-empty non-inverted case-insensitive", function() {
+ it("defines correct constants", function() {
+ expect(pass).toChangeAST(
+ 'start = [a]i',
+ constsDetails(['/^[a]/i', '"[a]i"'])
+ );
+ });
+ });
+
+ describe("non-empty complex", function() {
+ it("defines correct constants", function() {
+ expect(pass).toChangeAST(
+ 'start = [ab-def-hij-l]',
+ constsDetails(['/^[ab-def-hij-l]/', '"[ab-def-hij-l]"'])
+ );
+ });
+ });
+
+ describe("empty non-inverted", function() {
+ it("defines correct constants", function() {
+ expect(pass).toChangeAST(
+ 'start = []',
+ constsDetails(['/^(?!)/', '"[]"'])
+ );
+ });
+ });
+
+ describe("empty inverted", function() {
+ it("defines correct constants", function() {
+ expect(pass).toChangeAST(
+ 'start = [^]',
+ constsDetails(['/^[\\S\\s]/', '"[^]"'])
+ );
+ });
+ });
+ });
+
+ describe("for any", function() {
+ var grammar = 'start = .';
+
+ it("generates bytecode", function() {
+ expect(pass).toChangeAST(grammar, bytecodeDetails([
+ 14, 2, 2, // MATCH_ANY
+ 18, 1, // * ACCEPT_N
+ 20, 0 // * FAIL
+ ]));
+ });
+
+ it("defines correct constants", function() {
+ expect(pass).toChangeAST(grammar, constsDetails(['"any character"']));
+ });
+ });
+});
diff --git a/spec/generated-parser.spec.js b/spec/generated-parser.spec.js
index 7c38a47..a904549 100644
--- a/spec/generated-parser.spec.js
+++ b/spec/generated-parser.spec.js
@@ -1,6 +1,9 @@
describe("generated parser", function() {
function vary(names, block) {
- var values = { cache: [false, true] };
+ var values = {
+ cache: [false, true],
+ optimize: ["speed", "size"]
+ };
function varyStep(names, options) {
var clonedOptions = {}, key, name, i;
@@ -32,7 +35,7 @@ describe("generated parser", function() {
}
function varyAll(block) {
- vary(["cache"], block);
+ vary(["cache", "optimize"], block);
}
beforeEach(function() {
diff --git a/spec/index.html b/spec/index.html
index ac58f7b..c1b2b25 100644
--- a/spec/index.html
+++ b/spec/index.html
@@ -12,7 +12,7 @@
-
+