Improve indentation of variable declarations

Before this commit, continuation lines of multi-line values in variable
declaration initializers were aligned with the variable name:

  let foo = {
        a: 5,
        b: 6
      };

This was highly irregular, maintenance intensive, and made declarations
look different from assignments.

This commit changes the indentation to be more regular and similar to
assignments:

  let foo = {
    a: 5,
    b: 6
  };
redux
David Majda 8 years ago
parent b5eb1a0ec4
commit 7ca229a432

@ -62,9 +62,9 @@ $("#run").click(() => {
let runCount = parseInt($("#run-count").val(), 10); let runCount = parseInt($("#run-count").val(), 10);
let options = { let options = {
cache: $("#cache").is(":checked"), cache: $("#cache").is(":checked"),
optimize: $("#optimize").val() optimize: $("#optimize").val()
}; };
if (isNaN(runCount) || runCount <= 0) { if (isNaN(runCount) || runCount <= 0) {
alert("Number of runs must be a positive integer."); alert("Number of runs must be a positive integer.");

@ -10,22 +10,22 @@ let Runner = {
// Queue // Queue
let Q = { let Q = {
functions: [], functions: [],
add: function(f) { add: function(f) {
this.functions.push(f); this.functions.push(f);
}, },
run: function() { run: function() {
if (this.functions.length > 0) { if (this.functions.length > 0) {
this.functions.shift()(); this.functions.shift()();
// We can't use |arguments.callee| here because |this| would get // We can't use |arguments.callee| here because |this| would get
// messed-up in that case. // messed-up in that case.
setTimeout(() => { Q.run(); }, 0); setTimeout(() => { Q.run(); }, 0);
} }
} }
}; };
// The benchmark itself is factored out into several functions (some of them // The benchmark itself is factored out into several functions (some of them
// generated), which are enqueued and run one by one using |setTimeout|. We // generated), which are enqueued and run one by one using |setTimeout|. We

@ -348,10 +348,10 @@ function generateBytecode(ast) {
let emitCall = node.expression.type !== "sequence" let emitCall = node.expression.type !== "sequence"
|| node.expression.elements.length === 0; || node.expression.elements.length === 0;
let expressionCode = generate(node.expression, { let expressionCode = generate(node.expression, {
sp: context.sp + (emitCall ? 1 : 0), sp: context.sp + (emitCall ? 1 : 0),
env: env, env: env,
action: node action: node
}); });
let functionIndex = addFunctionConst(Object.keys(env), node.code); let functionIndex = addFunctionConst(Object.keys(env), node.code);
return emitCall return emitCall
@ -482,10 +482,10 @@ function generateBytecode(ast) {
zero_or_more: function(node, context) { zero_or_more: function(node, context) {
let expressionCode = generate(node.expression, { let expressionCode = generate(node.expression, {
sp: context.sp + 1, sp: context.sp + 1,
env: cloneEnv(context.env), env: cloneEnv(context.env),
action: null action: null
}); });
return buildSequence( return buildSequence(
[op.PUSH_EMPTY_ARRAY], [op.PUSH_EMPTY_ARRAY],
@ -497,10 +497,10 @@ function generateBytecode(ast) {
one_or_more: function(node, context) { one_or_more: function(node, context) {
let expressionCode = generate(node.expression, { let expressionCode = generate(node.expression, {
sp: context.sp + 1, sp: context.sp + 1,
env: cloneEnv(context.env), env: cloneEnv(context.env),
action: null action: null
}); });
return buildSequence( return buildSequence(
[op.PUSH_EMPTY_ARRAY], [op.PUSH_EMPTY_ARRAY],
@ -569,30 +569,30 @@ function generateBytecode(ast) {
"class": function(node) { "class": function(node) {
let regexp = "/^[" let regexp = "/^["
+ (node.inverted ? "^" : "") + (node.inverted ? "^" : "")
+ node.parts.map(part => + node.parts.map(part =>
Array.isArray(part) Array.isArray(part)
? js.regexpClassEscape(part[0]) ? js.regexpClassEscape(part[0])
+ "-" + "-"
+ js.regexpClassEscape(part[1]) + js.regexpClassEscape(part[1])
: js.regexpClassEscape(part) : js.regexpClassEscape(part)
).join("") ).join("")
+ "]/" + (node.ignoreCase ? "i" : ""); + "]/" + (node.ignoreCase ? "i" : "");
let parts = "[" let parts = "["
+ node.parts.map(part => + node.parts.map(part =>
Array.isArray(part) Array.isArray(part)
? "[\"" + js.stringEscape(part[0]) + "\", \"" + js.stringEscape(part[1]) + "\"]" ? "[\"" + js.stringEscape(part[0]) + "\", \"" + js.stringEscape(part[1]) + "\"]"
: "\"" + js.stringEscape(part) + "\"" : "\"" + js.stringEscape(part) + "\""
).join(", ") ).join(", ")
+ "]"; + "]";
let regexpIndex = addConst(regexp); let regexpIndex = addConst(regexp);
let expectedIndex = addConst( let expectedIndex = addConst(
"peg$classExpectation(" "peg$classExpectation("
+ parts + ", " + parts + ", "
+ node.inverted + ", " + node.inverted + ", "
+ node.ignoreCase + node.ignoreCase
+ ")" + ")"
); );
return buildCondition( return buildCondition(
[op.MATCH_REGEXP, regexpIndex], [op.MATCH_REGEXP, regexpIndex],

@ -411,41 +411,41 @@ function generateJS(ast, options) {
function s(i) { return "s" + i; } // |stack[i]| of the abstract machine function s(i) { return "s" + i; } // |stack[i]| of the abstract machine
let stack = { let stack = {
sp: -1, sp: -1,
maxSp: -1, maxSp: -1,
push: function(exprCode) { push: function(exprCode) {
let code = s(++this.sp) + " = " + exprCode + ";"; let code = s(++this.sp) + " = " + exprCode + ";";
if (this.sp > this.maxSp) { this.maxSp = this.sp; } if (this.sp > this.maxSp) { this.maxSp = this.sp; }
return code; return code;
}, },
pop: function(n) { pop: function(n) {
if (n === undefined) { if (n === undefined) {
return s(this.sp--); return s(this.sp--);
} else { } else {
let values = Array(n); let values = Array(n);
for (var i = 0; i < n; i++) { for (var i = 0; i < n; i++) {
values[i] = s(this.sp - n + 1 + i); values[i] = s(this.sp - n + 1 + i);
} }
this.sp -= n; this.sp -= n;
return values; return values;
} }
}, },
top: function() { top: function() {
return s(this.sp); return s(this.sp);
}, },
index: function(i) { index: function(i) {
return s(this.sp - i); return s(this.sp - i);
} }
}; };
function compile(bc) { function compile(bc) {
let ip = 0; let ip = 0;
@ -512,10 +512,10 @@ function generateJS(ast, options) {
let paramsLength = bc[ip + baseLength - 1]; let paramsLength = bc[ip + baseLength - 1];
let value = c(bc[ip + 1]) + "(" let value = c(bc[ip + 1]) + "("
+ bc.slice(ip + baseLength, ip + baseLength + paramsLength).map( + bc.slice(ip + baseLength, ip + baseLength + paramsLength).map(
p => stack.index(p) p => stack.index(p)
).join(", ") ).join(", ")
+ ")"; + ")";
stack.pop(bc[ip + 2]); stack.pop(bc[ip + 2]);
parts.push(stack.push(value)); parts.push(stack.push(value));
ip += baseLength + paramsLength; ip += baseLength + paramsLength;
@ -767,32 +767,32 @@ function generateJS(ast, options) {
"", "",
"peg$SyntaxError.buildMessage = function(expected, found) {", "peg$SyntaxError.buildMessage = function(expected, found) {",
" var DESCRIBE_EXPECTATION_FNS = {", " var DESCRIBE_EXPECTATION_FNS = {",
" literal: function(expectation) {", " literal: function(expectation) {",
" return \"\\\"\" + literalEscape(expectation.text) + \"\\\"\";", " return \"\\\"\" + literalEscape(expectation.text) + \"\\\"\";",
" },", " },",
"", "",
" \"class\": function(expectation) {", " \"class\": function(expectation) {",
" var escapedParts = expectation.parts.map(function(part) {", " var escapedParts = expectation.parts.map(function(part) {",
" return Array.isArray(part)", " return Array.isArray(part)",
" ? classEscape(part[0]) + \"-\" + classEscape(part[1])", " ? classEscape(part[0]) + \"-\" + classEscape(part[1])",
" : classEscape(part);", " : classEscape(part);",
" });", " });",
"", "",
" return \"[\" + (expectation.inverted ? \"^\" : \"\") + escapedParts + \"]\";", " return \"[\" + (expectation.inverted ? \"^\" : \"\") + escapedParts + \"]\";",
" },", " },",
"", "",
" any: function(expectation) {", " any: function(expectation) {",
" return \"any character\";", " return \"any character\";",
" },", " },",
"", "",
" end: function(expectation) {", " end: function(expectation) {",
" return \"end of input\";", " return \"end of input\";",
" },", " },",
"", "",
" other: function(expectation) {", " other: function(expectation) {",
" return expectation.description;", " return expectation.description;",
" }", " }",
" };", " };",
"", "",
" function hex(ch) {", " function hex(ch) {",
" return ch.charCodeAt(0).toString(16).toUpperCase();", " return ch.charCodeAt(0).toString(16).toUpperCase();",
@ -935,10 +935,10 @@ function generateJS(ast, options) {
if (options.optimize === "size") { if (options.optimize === "size") {
let startRuleIndices = "{ " let startRuleIndices = "{ "
+ options.allowedStartRules.map( + options.allowedStartRules.map(
r => r + ": " + asts.indexOfRule(ast, r) r => r + ": " + asts.indexOfRule(ast, r)
).join(", ") ).join(", ")
+ " }"; + " }";
let startRuleIndex = asts.indexOfRule(ast, options.allowedStartRules[0]); let startRuleIndex = asts.indexOfRule(ast, options.allowedStartRules[0]);
parts.push([ parts.push([
@ -947,10 +947,10 @@ function generateJS(ast, options) {
].join("\n")); ].join("\n"));
} else { } else {
let startRuleFunctions = "{ " let startRuleFunctions = "{ "
+ options.allowedStartRules.map( + options.allowedStartRules.map(
r => r + ": peg$parse" + r r => r + ": peg$parse" + r
).join(", ") ).join(", ")
+ " }"; + " }";
let startRuleFunction = "peg$parse" + options.allowedStartRules[0]; let startRuleFunction = "peg$parse" + options.allowedStartRules[0];
parts.push([ parts.push([
@ -984,10 +984,10 @@ function generateJS(ast, options) {
if (options.trace) { if (options.trace) {
if (options.optimize === "size") { if (options.optimize === "size") {
let ruleNames = "[" let ruleNames = "["
+ ast.rules.map( + ast.rules.map(
r => "\"" + js.stringEscape(r.name) + "\"" r => "\"" + js.stringEscape(r.name) + "\""
).join(", ") ).join(", ")
+ "]"; + "]";
parts.push([ parts.push([
" var peg$ruleNames = " + ruleNames + ";", " var peg$ruleNames = " + ruleNames + ";",
@ -1272,10 +1272,10 @@ function generateJS(ast, options) {
let dependencyVars = Object.keys(options.dependencies); let dependencyVars = Object.keys(options.dependencies);
let dependencyIds = dependencyIds.map(v => options.dependencies[v]); let dependencyIds = dependencyIds.map(v => options.dependencies[v]);
let dependencies = "[" let dependencies = "["
+ dependencyIds.map( + dependencyIds.map(
id => "\"" + js.stringEscape(id) + "\"" id => "\"" + js.stringEscape(id) + "\""
).join(", ") ).join(", ")
+ "]"; + "]";
let params = dependencyVars.join(", "); let params = dependencyVars.join(", ");
return [ return [
@ -1310,13 +1310,13 @@ function generateJS(ast, options) {
let dependencyVars = Object.keys(options.dependencies); let dependencyVars = Object.keys(options.dependencies);
let dependencyIds = dependencyIds.map(v => options.dependencies[v]); let dependencyIds = dependencyIds.map(v => options.dependencies[v]);
let dependencies = "[" let dependencies = "["
+ dependencyIds.map( + dependencyIds.map(
id => "\"" + js.stringEscape(id) + "\"" id => "\"" + js.stringEscape(id) + "\""
).join(", ") ).join(", ")
+ "]"; + "]";
let requires = dependencyIds.map( let requires = dependencyIds.map(
id => "require(\"" + js.stringEscape(id) + "\")" id => "require(\"" + js.stringEscape(id) + "\")"
).join(", "); ).join(", ");
let params = dependencyVars.join(", "); let params = dependencyVars.join(", ");
parts.push([ parts.push([

@ -26,39 +26,39 @@ let visitor = {
} }
const DEFAULT_FUNCTIONS = { const DEFAULT_FUNCTIONS = {
grammar: function(node) { grammar: function(node) {
let extraArgs = Array.prototype.slice.call(arguments, 1); let extraArgs = Array.prototype.slice.call(arguments, 1);
if (node.initializer) { if (node.initializer) {
visit.apply(null, [node.initializer].concat(extraArgs)); visit.apply(null, [node.initializer].concat(extraArgs));
} }
node.rules.forEach(rule => { node.rules.forEach(rule => {
visit.apply(null, [rule].concat(extraArgs)); visit.apply(null, [rule].concat(extraArgs));
}); });
}, },
initializer: visitNop, initializer: visitNop,
rule: visitExpression, rule: visitExpression,
named: visitExpression, named: visitExpression,
choice: visitChildren("alternatives"), choice: visitChildren("alternatives"),
action: visitExpression, action: visitExpression,
sequence: visitChildren("elements"), sequence: visitChildren("elements"),
labeled: visitExpression, labeled: visitExpression,
text: visitExpression, text: visitExpression,
simple_and: visitExpression, simple_and: visitExpression,
simple_not: visitExpression, simple_not: visitExpression,
optional: visitExpression, optional: visitExpression,
zero_or_more: visitExpression, zero_or_more: visitExpression,
one_or_more: visitExpression, one_or_more: visitExpression,
group: visitExpression, group: visitExpression,
semantic_and: visitNop, semantic_and: visitNop,
semantic_not: visitNop, semantic_not: visitNop,
rule_ref: visitNop, rule_ref: visitNop,
literal: visitNop, literal: visitNop,
"class": visitNop, "class": visitNop,
any: visitNop any: visitNop
}; };
Object.keys(DEFAULT_FUNCTIONS).forEach(type => { Object.keys(DEFAULT_FUNCTIONS).forEach(type => {
if (!functions.hasOwnProperty(type)) { if (!functions.hasOwnProperty(type)) {

@ -28,32 +28,32 @@ peg$subclass(peg$SyntaxError, Error);
peg$SyntaxError.buildMessage = function(expected, found) { peg$SyntaxError.buildMessage = function(expected, found) {
var DESCRIBE_EXPECTATION_FNS = { var DESCRIBE_EXPECTATION_FNS = {
literal: function(expectation) { literal: function(expectation) {
return "\"" + literalEscape(expectation.text) + "\""; return "\"" + literalEscape(expectation.text) + "\"";
}, },
"class": function(expectation) { "class": function(expectation) {
var escapedParts = expectation.parts.map(function(part) { var escapedParts = expectation.parts.map(function(part) {
return Array.isArray(part) return Array.isArray(part)
? classEscape(part[0]) + "-" + classEscape(part[1]) ? classEscape(part[0]) + "-" + classEscape(part[1])
: classEscape(part); : classEscape(part);
}); });
return "[" + (expectation.inverted ? "^" : "") + escapedParts + "]"; return "[" + (expectation.inverted ? "^" : "") + escapedParts + "]";
}, },
any: function(expectation) { any: function(expectation) {
return "any character"; return "any character";
}, },
end: function(expectation) { end: function(expectation) {
return "end of input"; return "end of input";
}, },
other: function(expectation) { other: function(expectation) {
return expectation.description; return expectation.description;
} }
}; };
function hex(ch) { function hex(ch) {
return ch.charCodeAt(0).toString(16).toUpperCase(); return ch.charCodeAt(0).toString(16).toUpperCase();

@ -33,9 +33,9 @@ let peg = {
let plugins = "plugins" in options ? options.plugins : []; let plugins = "plugins" in options ? options.plugins : [];
let config = { let config = {
parser: peg.parser, parser: peg.parser,
passes: convertPasses(peg.compiler.passes) passes: convertPasses(peg.compiler.passes)
}; };
plugins.forEach(p => { p.use(config, options); }); plugins.forEach(p => { p.use(config, options); });

@ -21,10 +21,10 @@ describe("generated parser API", function() {
describe("start rule", function() { describe("start rule", function() {
let parser = peg.generate([ let parser = peg.generate([
"a = 'x' { return 'a'; }", "a = 'x' { return 'a'; }",
"b = 'x' { return 'b'; }", "b = 'x' { return 'b'; }",
"c = 'x' { return 'c'; }" "c = 'x' { return 'c'; }"
].join("\n"), { allowedStartRules: ["b", "c"] }); ].join("\n"), { allowedStartRules: ["b", "c"] });
describe("when |startRule| is not set", function() { describe("when |startRule| is not set", function() {
it("starts parsing from the first allowed rule", function() { it("starts parsing from the first allowed rule", function() {
@ -48,10 +48,10 @@ describe("generated parser API", function() {
describe("tracing", function() { describe("tracing", function() {
let parser = peg.generate([ let parser = peg.generate([
"start = a / b", "start = a / b",
"a = 'a'", "a = 'a'",
"b = 'b'" "b = 'b'"
].join("\n"), { trace: true }); ].join("\n"), { trace: true });
describe("default tracer", function() { describe("default tracer", function() {
it("traces using console.log (if console is defined)", function() { it("traces using console.log (if console is defined)", function() {

@ -21,10 +21,10 @@ describe("PEG.js API", function() {
describe("allowed start rules", function() { describe("allowed start rules", function() {
let grammar = [ let grammar = [
"a = 'x'", "a = 'x'",
"b = 'x'", "b = 'x'",
"c = 'x'" "c = 'x'"
].join("\n"); ].join("\n");
// The |allowedStartRules| option is implemented separately for each // The |allowedStartRules| option is implemented separately for each
// optimization mode, so we need to test it in both. // optimization mode, so we need to test it in both.
@ -82,10 +82,10 @@ describe("PEG.js API", function() {
describe("intermediate results caching", function() { describe("intermediate results caching", function() {
let grammar = [ let grammar = [
"{ var n = 0; }", "{ var n = 0; }",
"start = (a 'b') / (a 'c') { return n; }", "start = (a 'b') / (a 'c') { return n; }",
"a = 'a' { n++; }" "a = 'a' { n++; }"
].join("\n"); ].join("\n");
describe("when |cache| is not set", function() { describe("when |cache| is not set", function() {
it("generated parser doesn't cache intermediate parse results", function() { it("generated parser doesn't cache intermediate parse results", function() {

@ -40,10 +40,10 @@ describe("plugin API", function() {
it("is called for each plugin", function() { it("is called for each plugin", function() {
let pluginsUsed = [false, false, false]; let pluginsUsed = [false, false, false];
let plugins = [ let plugins = [
{ use: function() { pluginsUsed[0] = true; } }, { use: function() { pluginsUsed[0] = true; } },
{ use: function() { pluginsUsed[1] = true; } }, { use: function() { pluginsUsed[1] = true; } },
{ use: function() { pluginsUsed[2] = true; } } { use: function() { pluginsUsed[2] = true; } }
]; ];
peg.generate(grammar, { plugins: plugins }); peg.generate(grammar, { plugins: plugins });
@ -52,40 +52,40 @@ describe("plugin API", function() {
it("receives configuration", function() { it("receives configuration", function() {
let plugin = { let plugin = {
use: function(config) { use: function(config) {
expect(config).toBeObject(); expect(config).toBeObject();
expect(config.parser).toBeObject(); expect(config.parser).toBeObject();
expect(config.parser.parse("start = 'a'")).toBeObject(); expect(config.parser.parse("start = 'a'")).toBeObject();
expect(config.passes).toBeObject(); expect(config.passes).toBeObject();
expect(config.passes.check).toBeArray(); expect(config.passes.check).toBeArray();
config.passes.check.forEach(pass => { config.passes.check.forEach(pass => {
expect(pass).toBeFunction(); expect(pass).toBeFunction();
}); });
expect(config.passes.transform).toBeArray(); expect(config.passes.transform).toBeArray();
config.passes.transform.forEach(pass => { config.passes.transform.forEach(pass => {
expect(pass).toBeFunction(); expect(pass).toBeFunction();
}); });
expect(config.passes.generate).toBeArray(); expect(config.passes.generate).toBeArray();
config.passes.generate.forEach(pass => { config.passes.generate.forEach(pass => {
expect(pass).toBeFunction(); expect(pass).toBeFunction();
}); });
} }
}; };
peg.generate(grammar, { plugins: [plugin] }); peg.generate(grammar, { plugins: [plugin] });
}); });
it("receives options", function() { it("receives options", function() {
let plugin = { let plugin = {
use: function(config, options) { use: function(config, options) {
expect(options).toEqual(generateOptions); expect(options).toEqual(generateOptions);
} }
}; };
let generateOptions = { plugins: [plugin], foo: 42 }; let generateOptions = { plugins: [plugin], foo: 42 };
peg.generate(grammar, generateOptions); peg.generate(grammar, generateOptions);
@ -93,25 +93,25 @@ describe("plugin API", function() {
it("can replace parser", function() { it("can replace parser", function() {
let plugin = { let plugin = {
use: function(config) { use: function(config) {
let parser = peg.generate([ let parser = peg.generate([
"start = .* {", "start = .* {",
" return {", " return {",
" type: 'grammar',", " type: 'grammar',",
" rules: [", " rules: [",
" {", " {",
" type: 'rule',", " type: 'rule',",
" name: 'start',", " name: 'start',",
" expression: { type: 'literal', value: text(), ignoreCase: false }", " expression: { type: 'literal', value: text(), ignoreCase: false }",
" }", " }",
" ]", " ]",
" };", " };",
"}" "}"
].join("\n")); ].join("\n"));
config.parser = parser; config.parser = parser;
} }
}; };
let parser = peg.generate("a", { plugins: [plugin] }); let parser = peg.generate("a", { plugins: [plugin] });
expect(parser.parse("a")).toBe("a"); expect(parser.parse("a")).toBe("a");
@ -119,14 +119,14 @@ describe("plugin API", function() {
it("can change compiler passes", function() { it("can change compiler passes", function() {
let plugin = { let plugin = {
use: function(config) { use: function(config) {
let pass = ast => { let pass = ast => {
ast.code = "({ parse: function() { return 42; } })"; ast.code = "({ parse: function() { return 42; } })";
};
config.passes.generate = [pass];
}
}; };
config.passes.generate = [pass];
}
};
let parser = peg.generate(grammar, { plugins: [plugin] }); let parser = peg.generate(grammar, { plugins: [plugin] });
expect(parser.parse("a")).toBe(42); expect(parser.parse("a")).toBe(42);
@ -134,19 +134,19 @@ describe("plugin API", function() {
it("can change options", function() { it("can change options", function() {
let grammar = [ let grammar = [
"a = 'x'", "a = 'x'",
"b = 'x'", "b = 'x'",
"c = 'x'" "c = 'x'"
].join("\n"); ].join("\n");
let plugin = { let plugin = {
use: function(config, options) { use: function(config, options) {
options.allowedStartRules = ["b", "c"]; options.allowedStartRules = ["b", "c"];
} }
}; };
let parser = peg.generate(grammar, { let parser = peg.generate(grammar, {
allowedStartRules: ["a"], allowedStartRules: ["a"],
plugins: [plugin] plugins: [plugin]
}); });
expect(() => { parser.parse("x", { startRule: "a" }); }).toThrow(); expect(() => { parser.parse("x", { startRule: "a" }); }).toThrow();
expect(parser.parse("x", { startRule: "b" })).toBe("x"); expect(parser.parse("x", { startRule: "b" })).toBe("x");

@ -18,15 +18,15 @@ describe("generated parser behavior", function() {
} }
let optionsVariants = [ let optionsVariants = [
{ cache: false, optimize: "speed", trace: false }, { cache: false, optimize: "speed", trace: false },
{ cache: false, optimize: "speed", trace: true }, { cache: false, optimize: "speed", trace: true },
{ cache: false, optimize: "size", trace: false }, { cache: false, optimize: "size", trace: false },
{ cache: false, optimize: "size", trace: true }, { cache: false, optimize: "size", trace: true },
{ cache: true, optimize: "speed", trace: false }, { cache: true, optimize: "speed", trace: false },
{ cache: true, optimize: "speed", trace: true }, { cache: true, optimize: "speed", trace: true },
{ cache: true, optimize: "size", trace: false }, { cache: true, optimize: "size", trace: false },
{ cache: true, optimize: "size", trace: true } { cache: true, optimize: "size", trace: true }
]; ];
optionsVariants.forEach(variant => { optionsVariants.forEach(variant => {
describe( describe(
@ -131,9 +131,9 @@ describe("generated parser behavior", function() {
describe("initializer", function() { describe("initializer", function() {
it("executes the code before parsing starts", function() { it("executes the code before parsing starts", function() {
let parser = peg.generate([ let parser = peg.generate([
"{ var result = 42; }", "{ var result = 42; }",
"start = 'a' { return result; }" "start = 'a' { return result; }"
].join("\n"), options); ].join("\n"), options);
expect(parser).toParse("a", 42); expect(parser).toParse("a", 42);
}); });
@ -141,9 +141,9 @@ describe("generated parser behavior", function() {
describe("available variables and functions", function() { describe("available variables and functions", function() {
it("|options| contains options", function() { it("|options| contains options", function() {
let parser = peg.generate([ let parser = peg.generate([
"{ var result = options; }", "{ var result = options; }",
"start = 'a' { return result; }" "start = 'a' { return result; }"
].join("\n"), options); ].join("\n"), options);
expect(parser).toParse("a", { a: 42 }, { a: 42 }); expect(parser).toParse("a", { a: 42 }, { a: 42 });
}); });
@ -154,20 +154,20 @@ describe("generated parser behavior", function() {
if (options.cache) { if (options.cache) {
it("caches rule match results", function() { it("caches rule match results", function() {
let parser = peg.generate([ let parser = peg.generate([
"{ var n = 0; }", "{ var n = 0; }",
"start = (a 'b') / (a 'c') { return n; }", "start = (a 'b') / (a 'c') { return n; }",
"a = 'a' { n++; }" "a = 'a' { n++; }"
].join("\n"), options); ].join("\n"), options);
expect(parser).toParse("ac", 1); expect(parser).toParse("ac", 1);
}); });
} else { } else {
it("doesn't cache rule match results", function() { it("doesn't cache rule match results", function() {
let parser = peg.generate([ let parser = peg.generate([
"{ var n = 0; }", "{ var n = 0; }",
"start = (a 'b') / (a 'c') { return n; }", "start = (a 'b') / (a 'c') { return n; }",
"a = 'a' { n++; }" "a = 'a' { n++; }"
].join("\n"), options); ].join("\n"), options);
expect(parser).toParse("ac", 2); expect(parser).toParse("ac", 2);
}); });
@ -387,9 +387,9 @@ describe("generated parser behavior", function() {
describe("when referenced rule's expression matches", function() { describe("when referenced rule's expression matches", function() {
it("returns its result", function() { it("returns its result", function() {
let parser = peg.generate([ let parser = peg.generate([
"start = a", "start = a",
"a = 'a'" "a = 'a'"
].join("\n"), options); ].join("\n"), options);
expect(parser).toParse("a", "a"); expect(parser).toParse("a", "a");
}); });
@ -398,9 +398,9 @@ describe("generated parser behavior", function() {
describe("when referenced rule's expression doesn't match", function() { describe("when referenced rule's expression doesn't match", function() {
it("reports match failure", function() { it("reports match failure", function() {
let parser = peg.generate([ let parser = peg.generate([
"start = a", "start = a",
"a = 'a'" "a = 'a'"
].join("\n"), options); ].join("\n"), options);
expect(parser).toFailToParse("b"); expect(parser).toFailToParse("b");
}); });
@ -431,78 +431,78 @@ describe("generated parser behavior", function() {
describe("in containing sequence", function() { describe("in containing sequence", function() {
it("can access variables defined by preceding labeled elements", function() { it("can access variables defined by preceding labeled elements", function() {
let parser = peg.generate( let parser = peg.generate(
"start = a:'a' &{ return a === 'a'; }", "start = a:'a' &{ return a === 'a'; }",
options options
); );
expect(parser).toParse("a"); expect(parser).toParse("a");
}); });
it("cannot access variable defined by labeled predicate element", function() { it("cannot access variable defined by labeled predicate element", function() {
let parser = peg.generate( let parser = peg.generate(
"start = 'a' b:&{ return b === undefined; } 'c'", "start = 'a' b:&{ return b === undefined; } 'c'",
options options
); );
expect(parser).toFailToParse("ac"); expect(parser).toFailToParse("ac");
}); });
it("cannot access variables defined by following labeled elements", function() { it("cannot access variables defined by following labeled elements", function() {
let parser = peg.generate( let parser = peg.generate(
"start = &{ return a === 'a'; } a:'a'", "start = &{ return a === 'a'; } a:'a'",
options options
); );
expect(parser).toFailToParse("a"); expect(parser).toFailToParse("a");
}); });
it("cannot access variables defined by subexpressions", function() { it("cannot access variables defined by subexpressions", function() {
let testcases = [ let testcases = [
{ {
grammar: "start = (a:'a') &{ return a === 'a'; }", grammar: "start = (a:'a') &{ return a === 'a'; }",
input: "a" input: "a"
}, },
{ {
grammar: "start = (a:'a')? &{ return a === 'a'; }", grammar: "start = (a:'a')? &{ return a === 'a'; }",
input: "a" input: "a"
}, },
{ {
grammar: "start = (a:'a')* &{ return a === 'a'; }", grammar: "start = (a:'a')* &{ return a === 'a'; }",
input: "a" input: "a"
}, },
{ {
grammar: "start = (a:'a')+ &{ return a === 'a'; }", grammar: "start = (a:'a')+ &{ return a === 'a'; }",
input: "a" input: "a"
}, },
{ {
grammar: "start = $(a:'a') &{ return a === 'a'; }", grammar: "start = $(a:'a') &{ return a === 'a'; }",
input: "a" input: "a"
}, },
{ {
grammar: "start = &(a:'a') 'a' &{ return a === 'a'; }", grammar: "start = &(a:'a') 'a' &{ return a === 'a'; }",
input: "a" input: "a"
}, },
{ {
grammar: "start = !(a:'a') 'b' &{ return a === 'a'; }", grammar: "start = !(a:'a') 'b' &{ return a === 'a'; }",
input: "b" input: "b"
}, },
{ {
grammar: "start = b:(a:'a') &{ return a === 'a'; }", grammar: "start = b:(a:'a') &{ return a === 'a'; }",
input: "a" input: "a"
}, },
{ {
grammar: "start = ('a' b:'b' 'c') &{ return b === 'b'; }", grammar: "start = ('a' b:'b' 'c') &{ return b === 'b'; }",
input: "abc" input: "abc"
}, },
{ {
grammar: "start = (a:'a' { return a; }) &{ return a === 'a'; }", grammar: "start = (a:'a' { return a; }) &{ return a === 'a'; }",
input: "a" input: "a"
}, },
{ {
grammar: "start = ('a' / b:'b' / 'c') &{ return b === 'b'; }", grammar: "start = ('a' / b:'b' / 'c') &{ return b === 'b'; }",
input: "b" input: "b"
} }
]; ];
testcases.forEach(testcase => { testcases.forEach(testcase => {
let parser = peg.generate(testcase.grammar, options); let parser = peg.generate(testcase.grammar, options);
@ -514,27 +514,27 @@ describe("generated parser behavior", function() {
describe("in outer sequence", function() { describe("in outer sequence", function() {
it("can access variables defined by preceding labeled elements", function() { it("can access variables defined by preceding labeled elements", function() {
let parser = peg.generate( let parser = peg.generate(
"start = a:'a' ('b' &{ return a === 'a'; })", "start = a:'a' ('b' &{ return a === 'a'; })",
options options
); );
expect(parser).toParse("ab"); expect(parser).toParse("ab");
}); });
it("cannot access variable defined by labeled predicate element", function() { it("cannot access variable defined by labeled predicate element", function() {
let parser = peg.generate( let parser = peg.generate(
"start = 'a' b:('b' &{ return b === undefined; }) 'c'", "start = 'a' b:('b' &{ return b === undefined; }) 'c'",
options options
); );
expect(parser).toFailToParse("abc"); expect(parser).toFailToParse("abc");
}); });
it("cannot access variables defined by following labeled elements", function() { it("cannot access variables defined by following labeled elements", function() {
let parser = peg.generate( let parser = peg.generate(
"start = ('a' &{ return b === 'b'; }) b:'b'", "start = ('a' &{ return b === 'b'; }) b:'b'",
options options
); );
expect(parser).toFailToParse("ab"); expect(parser).toFailToParse("ab");
}); });
@ -544,18 +544,18 @@ describe("generated parser behavior", function() {
describe("initializer variables & functions", function() { describe("initializer variables & functions", function() {
it("can access variables defined in the initializer", function() { it("can access variables defined in the initializer", function() {
let parser = peg.generate([ let parser = peg.generate([
"{ var v = 42 }", "{ var v = 42 }",
"start = &{ return v === 42; }" "start = &{ return v === 42; }"
].join("\n"), options); ].join("\n"), options);
expect(parser).toParse(""); expect(parser).toParse("");
}); });
it("can access functions defined in the initializer", function() { it("can access functions defined in the initializer", function() {
let parser = peg.generate([ let parser = peg.generate([
"{ function f() { return 42; } }", "{ function f() { return 42; } }",
"start = &{ return f() === 42; }" "start = &{ return f() === 42; }"
].join("\n"), options); ].join("\n"), options);
expect(parser).toParse(""); expect(parser).toParse("");
}); });
@ -564,23 +564,23 @@ describe("generated parser behavior", function() {
describe("available variables & functions", function() { describe("available variables & functions", function() {
it("|options| contains options", function() { it("|options| contains options", function() {
let parser = peg.generate([ let parser = peg.generate([
"{ var result; }", "{ var result; }",
"start = &{ result = options; return true; } { return result; }" "start = &{ result = options; return true; } { return result; }"
].join("\n"), options); ].join("\n"), options);
expect(parser).toParse("", { a: 42 }, { a: 42 }); expect(parser).toParse("", { a: 42 }, { a: 42 });
}); });
it("|location| returns current location info", function() { it("|location| returns current location info", function() {
let parser = peg.generate([ let parser = peg.generate([
"{ var result; }", "{ var result; }",
"start = line (nl+ line)* { return result; }", "start = line (nl+ line)* { return result; }",
"line = thing (' '+ thing)*", "line = thing (' '+ thing)*",
"thing = digit / mark", "thing = digit / mark",
"digit = [0-9]", "digit = [0-9]",
"mark = &{ result = location(); return true; } 'x'", "mark = &{ result = location(); return true; } 'x'",
"nl = '\\r'? '\\n'" "nl = '\\r'? '\\n'"
].join("\n"), options); ].join("\n"), options);
expect(parser).toParse("1\n2\n\n3\n\n\n4 5 x", { expect(parser).toParse("1\n2\n\n3\n\n\n4 5 x", {
start: { offset: 13, line: 7, column: 5 }, start: { offset: 13, line: 7, column: 5 },
@ -624,78 +624,78 @@ describe("generated parser behavior", function() {
describe("in containing sequence", function() { describe("in containing sequence", function() {
it("can access variables defined by preceding labeled elements", function() { it("can access variables defined by preceding labeled elements", function() {
let parser = peg.generate( let parser = peg.generate(
"start = a:'a' !{ return a !== 'a'; }", "start = a:'a' !{ return a !== 'a'; }",
options options
); );
expect(parser).toParse("a"); expect(parser).toParse("a");
}); });
it("cannot access variable defined by labeled predicate element", function() { it("cannot access variable defined by labeled predicate element", function() {
let parser = peg.generate( let parser = peg.generate(
"start = 'a' b:!{ return b !== undefined; } 'c'", "start = 'a' b:!{ return b !== undefined; } 'c'",
options options
); );
expect(parser).toFailToParse("ac"); expect(parser).toFailToParse("ac");
}); });
it("cannot access variables defined by following labeled elements", function() { it("cannot access variables defined by following labeled elements", function() {
let parser = peg.generate( let parser = peg.generate(
"start = !{ return a !== 'a'; } a:'a'", "start = !{ return a !== 'a'; } a:'a'",
options options
); );
expect(parser).toFailToParse("a"); expect(parser).toFailToParse("a");
}); });
it("cannot access variables defined by subexpressions", function() { it("cannot access variables defined by subexpressions", function() {
let testcases = [ let testcases = [
{ {
grammar: "start = (a:'a') !{ return a !== 'a'; }", grammar: "start = (a:'a') !{ return a !== 'a'; }",
input: "a" input: "a"
}, },
{ {
grammar: "start = (a:'a')? !{ return a !== 'a'; }", grammar: "start = (a:'a')? !{ return a !== 'a'; }",
input: "a" input: "a"
}, },
{ {
grammar: "start = (a:'a')* !{ return a !== 'a'; }", grammar: "start = (a:'a')* !{ return a !== 'a'; }",
input: "a" input: "a"
}, },
{ {
grammar: "start = (a:'a')+ !{ return a !== 'a'; }", grammar: "start = (a:'a')+ !{ return a !== 'a'; }",
input: "a" input: "a"
}, },
{ {
grammar: "start = $(a:'a') !{ return a !== 'a'; }", grammar: "start = $(a:'a') !{ return a !== 'a'; }",
input: "a" input: "a"
}, },
{ {
grammar: "start = &(a:'a') 'a' !{ return a !== 'a'; }", grammar: "start = &(a:'a') 'a' !{ return a !== 'a'; }",
input: "a" input: "a"
}, },
{ {
grammar: "start = !(a:'a') 'b' !{ return a !== 'a'; }", grammar: "start = !(a:'a') 'b' !{ return a !== 'a'; }",
input: "b" input: "b"
}, },
{ {
grammar: "start = b:(a:'a') !{ return a !== 'a'; }", grammar: "start = b:(a:'a') !{ return a !== 'a'; }",
input: "a" input: "a"
}, },
{ {
grammar: "start = ('a' b:'b' 'c') !{ return b !== 'b'; }", grammar: "start = ('a' b:'b' 'c') !{ return b !== 'b'; }",
input: "abc" input: "abc"
}, },
{ {
grammar: "start = (a:'a' { return a; }) !{ return a !== 'a'; }", grammar: "start = (a:'a' { return a; }) !{ return a !== 'a'; }",
input: "a" input: "a"
}, },
{ {
grammar: "start = ('a' / b:'b' / 'c') !{ return b !== 'b'; }", grammar: "start = ('a' / b:'b' / 'c') !{ return b !== 'b'; }",
input: "b" input: "b"
} }
]; ];
testcases.forEach(testcase => { testcases.forEach(testcase => {
let parser = peg.generate(testcase.grammar, options); let parser = peg.generate(testcase.grammar, options);
@ -707,27 +707,27 @@ describe("generated parser behavior", function() {
describe("in outer sequence", function() { describe("in outer sequence", function() {
it("can access variables defined by preceding labeled elements", function() { it("can access variables defined by preceding labeled elements", function() {
let parser = peg.generate( let parser = peg.generate(
"start = a:'a' ('b' !{ return a !== 'a'; })", "start = a:'a' ('b' !{ return a !== 'a'; })",
options options
); );
expect(parser).toParse("ab"); expect(parser).toParse("ab");
}); });
it("cannot access variable defined by labeled predicate element", function() { it("cannot access variable defined by labeled predicate element", function() {
let parser = peg.generate( let parser = peg.generate(
"start = 'a' b:('b' !{ return b !== undefined; }) 'c'", "start = 'a' b:('b' !{ return b !== undefined; }) 'c'",
options options
); );
expect(parser).toFailToParse("abc"); expect(parser).toFailToParse("abc");
}); });
it("cannot access variables defined by following labeled elements", function() { it("cannot access variables defined by following labeled elements", function() {
let parser = peg.generate( let parser = peg.generate(
"start = ('a' !{ return b !== 'b'; }) b:'b'", "start = ('a' !{ return b !== 'b'; }) b:'b'",
options options
); );
expect(parser).toFailToParse("ab"); expect(parser).toFailToParse("ab");
}); });
@ -737,18 +737,18 @@ describe("generated parser behavior", function() {
describe("initializer variables & functions", function() { describe("initializer variables & functions", function() {
it("can access variables defined in the initializer", function() { it("can access variables defined in the initializer", function() {
let parser = peg.generate([ let parser = peg.generate([
"{ var v = 42 }", "{ var v = 42 }",
"start = !{ return v !== 42; }" "start = !{ return v !== 42; }"
].join("\n"), options); ].join("\n"), options);
expect(parser).toParse(""); expect(parser).toParse("");
}); });
it("can access functions defined in the initializer", function() { it("can access functions defined in the initializer", function() {
let parser = peg.generate([ let parser = peg.generate([
"{ function f() { return 42; } }", "{ function f() { return 42; } }",
"start = !{ return f() !== 42; }" "start = !{ return f() !== 42; }"
].join("\n"), options); ].join("\n"), options);
expect(parser).toParse(""); expect(parser).toParse("");
}); });
@ -757,23 +757,23 @@ describe("generated parser behavior", function() {
describe("available variables & functions", function() { describe("available variables & functions", function() {
it("|options| contains options", function() { it("|options| contains options", function() {
let parser = peg.generate([ let parser = peg.generate([
"{ var result; }", "{ var result; }",
"start = !{ result = options; return false; } { return result; }" "start = !{ result = options; return false; } { return result; }"
].join("\n"), options); ].join("\n"), options);
expect(parser).toParse("", { a: 42 }, { a: 42 }); expect(parser).toParse("", { a: 42 }, { a: 42 });
}); });
it("|location| returns current location info", function() { it("|location| returns current location info", function() {
let parser = peg.generate([ let parser = peg.generate([
"{ var result; }", "{ var result; }",
"start = line (nl+ line)* { return result; }", "start = line (nl+ line)* { return result; }",
"line = thing (' '+ thing)*", "line = thing (' '+ thing)*",
"thing = digit / mark", "thing = digit / mark",
"digit = [0-9]", "digit = [0-9]",
"mark = !{ result = location(); return false; } 'x'", "mark = !{ result = location(); return false; } 'x'",
"nl = '\\r'? '\\n'" "nl = '\\r'? '\\n'"
].join("\n"), options); ].join("\n"), options);
expect(parser).toParse("1\n2\n\n3\n\n\n4 5 x", { expect(parser).toParse("1\n2\n\n3\n\n\n4 5 x", {
start: { offset: 13, line: 7, column: 5 }, start: { offset: 13, line: 7, column: 5 },
@ -1010,60 +1010,60 @@ describe("generated parser behavior", function() {
it("can access variables defined by labeled sequence elements", function() { it("can access variables defined by labeled sequence elements", function() {
let parser = peg.generate( let parser = peg.generate(
"start = a:'a' b:'b' c:'c' { return [a, b, c]; }", "start = a:'a' b:'b' c:'c' { return [a, b, c]; }",
options options
); );
expect(parser).toParse("abc", ["a", "b", "c"]); expect(parser).toParse("abc", ["a", "b", "c"]);
}); });
it("cannot access variables defined by subexpressions", function() { it("cannot access variables defined by subexpressions", function() {
let testcases = [ let testcases = [
{ {
grammar: "start = (a:'a') { return a; }", grammar: "start = (a:'a') { return a; }",
input: "a" input: "a"
}, },
{ {
grammar: "start = (a:'a')? { return a; }", grammar: "start = (a:'a')? { return a; }",
input: "a" input: "a"
}, },
{ {
grammar: "start = (a:'a')* { return a; }", grammar: "start = (a:'a')* { return a; }",
input: "a" input: "a"
}, },
{ {
grammar: "start = (a:'a')+ { return a; }", grammar: "start = (a:'a')+ { return a; }",
input: "a" input: "a"
}, },
{ {
grammar: "start = $(a:'a') { return a; }", grammar: "start = $(a:'a') { return a; }",
input: "a" input: "a"
}, },
{ {
grammar: "start = &(a:'a') 'a' { return a; }", grammar: "start = &(a:'a') 'a' { return a; }",
input: "a" input: "a"
}, },
{ {
grammar: "start = !(a:'a') 'b' { return a; }", grammar: "start = !(a:'a') 'b' { return a; }",
input: "b" input: "b"
}, },
{ {
grammar: "start = b:(a:'a') { return a; }", grammar: "start = b:(a:'a') { return a; }",
input: "a" input: "a"
}, },
{ {
grammar: "start = ('a' b:'b' 'c') { return b; }", grammar: "start = ('a' b:'b' 'c') { return b; }",
input: "abc" input: "abc"
}, },
{ {
grammar: "start = (a:'a' { return a; }) { return a; }", grammar: "start = (a:'a' { return a; }) { return a; }",
input: "a" input: "a"
}, },
{ {
grammar: "start = ('a' / b:'b' / 'c') { return b; }", grammar: "start = ('a' / b:'b' / 'c') { return b; }",
input: "b" input: "b"
} }
]; ];
testcases.forEach(testcase => { testcases.forEach(testcase => {
let parser = peg.generate(testcase.grammar, options); let parser = peg.generate(testcase.grammar, options);
@ -1075,27 +1075,27 @@ describe("generated parser behavior", function() {
describe("in outer sequence", function() { describe("in outer sequence", function() {
it("can access variables defined by preceding labeled elements", function() { it("can access variables defined by preceding labeled elements", function() {
let parser = peg.generate( let parser = peg.generate(
"start = a:'a' ('b' { return a; })", "start = a:'a' ('b' { return a; })",
options options
); );
expect(parser).toParse("ab", ["a", "a"]); expect(parser).toParse("ab", ["a", "a"]);
}); });
it("cannot access variable defined by labeled action element", function() { it("cannot access variable defined by labeled action element", function() {
let parser = peg.generate( let parser = peg.generate(
"start = 'a' b:('b' { return b; }) c:'c'", "start = 'a' b:('b' { return b; }) c:'c'",
options options
); );
expect(parser).toFailToParse("abc"); expect(parser).toFailToParse("abc");
}); });
it("cannot access variables defined by following labeled elements", function() { it("cannot access variables defined by following labeled elements", function() {
let parser = peg.generate( let parser = peg.generate(
"start = ('a' { return b; }) b:'b'", "start = ('a' { return b; }) b:'b'",
options options
); );
expect(parser).toFailToParse("ab"); expect(parser).toFailToParse("ab");
}); });
@ -1105,18 +1105,18 @@ describe("generated parser behavior", function() {
describe("initializer variables & functions", function() { describe("initializer variables & functions", function() {
it("can access variables defined in the initializer", function() { it("can access variables defined in the initializer", function() {
let parser = peg.generate([ let parser = peg.generate([
"{ var v = 42 }", "{ var v = 42 }",
"start = 'a' { return v; }" "start = 'a' { return v; }"
].join("\n"), options); ].join("\n"), options);
expect(parser).toParse("a", 42); expect(parser).toParse("a", 42);
}); });
it("can access functions defined in the initializer", function() { it("can access functions defined in the initializer", function() {
let parser = peg.generate([ let parser = peg.generate([
"{ function f() { return 42; } }", "{ function f() { return 42; } }",
"start = 'a' { return f(); }" "start = 'a' { return f(); }"
].join("\n"), options); ].join("\n"), options);
expect(parser).toParse("a", 42); expect(parser).toParse("a", 42);
}); });
@ -1125,32 +1125,32 @@ describe("generated parser behavior", function() {
describe("available variables & functions", function() { describe("available variables & functions", function() {
it("|options| contains options", function() { it("|options| contains options", function() {
let parser = peg.generate( let parser = peg.generate(
"start = 'a' { return options; }", "start = 'a' { return options; }",
options options
); );
expect(parser).toParse("a", { a: 42 }, { a: 42 }); expect(parser).toParse("a", { a: 42 }, { a: 42 });
}); });
it("|text| returns text matched by the expression", function() { it("|text| returns text matched by the expression", function() {
let parser = peg.generate( let parser = peg.generate(
"start = 'a' { return text(); }", "start = 'a' { return text(); }",
options options
); );
expect(parser).toParse("a", "a"); expect(parser).toParse("a", "a");
}); });
it("|location| returns location info of the expression", function() { it("|location| returns location info of the expression", function() {
let parser = peg.generate([ let parser = peg.generate([
"{ var result; }", "{ var result; }",
"start = line (nl+ line)* { return result; }", "start = line (nl+ line)* { return result; }",
"line = thing (' '+ thing)*", "line = thing (' '+ thing)*",
"thing = digit / mark", "thing = digit / mark",
"digit = [0-9]", "digit = [0-9]",
"mark = 'x' { result = location(); }", "mark = 'x' { result = location(); }",
"nl = '\\r'? '\\n'" "nl = '\\r'? '\\n'"
].join("\n"), options); ].join("\n"), options);
expect(parser).toParse("1\n2\n\n3\n\n\n4 5 x", { expect(parser).toParse("1\n2\n\n3\n\n\n4 5 x", {
start: { offset: 13, line: 7, column: 5 }, start: { offset: 13, line: 7, column: 5 },
@ -1171,9 +1171,9 @@ describe("generated parser behavior", function() {
describe("|expected|", function() { describe("|expected|", function() {
it("terminates parsing and throws an exception", function() { it("terminates parsing and throws an exception", function() {
let parser = peg.generate( let parser = peg.generate(
"start = 'a' { expected('a'); }", "start = 'a' { expected('a'); }",
options options
); );
expect(parser).toFailToParse("a", { expect(parser).toFailToParse("a", {
message: "Expected a but \"a\" found.", message: "Expected a but \"a\" found.",
@ -1188,13 +1188,13 @@ describe("generated parser behavior", function() {
it("allows to set custom location info", function() { it("allows to set custom location info", function() {
let parser = peg.generate([ let parser = peg.generate([
"start = 'a' {", "start = 'a' {",
" expected('a', {", " expected('a', {",
" start: { offset: 1, line: 1, column: 2 },", " start: { offset: 1, line: 1, column: 2 },",
" end: { offset: 2, line: 1, column: 3 }", " end: { offset: 2, line: 1, column: 3 }",
" });", " });",
"}" "}"
].join("\n"), options); ].join("\n"), options);
expect(parser).toFailToParse("a", { expect(parser).toFailToParse("a", {
message: "Expected a but \"a\" found.", message: "Expected a but \"a\" found.",
@ -1211,9 +1211,9 @@ describe("generated parser behavior", function() {
describe("|error|", function() { describe("|error|", function() {
it("terminates parsing and throws an exception", function() { it("terminates parsing and throws an exception", function() {
let parser = peg.generate( let parser = peg.generate(
"start = 'a' { error('a'); }", "start = 'a' { error('a'); }",
options options
); );
expect(parser).toFailToParse("a", { expect(parser).toFailToParse("a", {
message: "a", message: "a",
@ -1228,13 +1228,13 @@ describe("generated parser behavior", function() {
it("allows to set custom location info", function() { it("allows to set custom location info", function() {
let parser = peg.generate([ let parser = peg.generate([
"start = 'a' {", "start = 'a' {",
" error('a', {", " error('a', {",
" start: { offset: 1, line: 1, column: 2 },", " start: { offset: 1, line: 1, column: 2 },",
" end: { offset: 2, line: 1, column: 3 }", " end: { offset: 2, line: 1, column: 3 }",
" });", " });",
"}" "}"
].join("\n"), options); ].join("\n"), options);
expect(parser).toFailToParse("a", { expect(parser).toFailToParse("a", {
message: "a", message: "a",
@ -1259,9 +1259,9 @@ describe("generated parser behavior", function() {
it("doesn't execute the code", function() { it("doesn't execute the code", function() {
let parser = peg.generate( let parser = peg.generate(
"start = 'a' { throw 'Boom!'; } / 'b'", "start = 'a' { throw 'Boom!'; } / 'b'",
options options
); );
expect(parser).toParse("b"); expect(parser).toParse("b");
}); });
@ -1438,11 +1438,11 @@ describe("generated parser behavior", function() {
it("reports position correctly in complex cases", function() { it("reports position correctly in complex cases", function() {
let parser = peg.generate([ let parser = peg.generate([
"start = line (nl+ line)*", "start = line (nl+ line)*",
"line = digit (' '+ digit)*", "line = digit (' '+ digit)*",
"digit = [0-9]", "digit = [0-9]",
"nl = '\\r'? '\\n'" "nl = '\\r'? '\\n'"
].join("\n"), options); ].join("\n"), options);
expect(parser).toFailToParse("1\n2\n\n3\n\n\n4 5 x", { expect(parser).toFailToParse("1\n2\n\n3\n\n\n4 5 x", {
location: { location: {
@ -1477,22 +1477,22 @@ describe("generated parser behavior", function() {
// Sum ← Product (('+' / '-') Product)* // Sum ← Product (('+' / '-') Product)*
// Expr ← Sum // Expr ← Sum
let parser = peg.generate([ let parser = peg.generate([
"Expr = Sum", "Expr = Sum",
"Sum = head:Product tail:(('+' / '-') Product)* {", "Sum = head:Product tail:(('+' / '-') Product)* {",
" return tail.reduce(function(result, element) {", " return tail.reduce(function(result, element) {",
" if (element[0] === '+') { return result + element[1]; }", " if (element[0] === '+') { return result + element[1]; }",
" if (element[0] === '-') { return result - element[1]; }", " if (element[0] === '-') { return result - element[1]; }",
" }, head);", " }, head);",
" }", " }",
"Product = head:Value tail:(('*' / '/') Value)* {", "Product = head:Value tail:(('*' / '/') Value)* {",
" return tail.reduce(function(result, element) {", " return tail.reduce(function(result, element) {",
" if (element[0] === '*') { return result * element[1]; }", " if (element[0] === '*') { return result * element[1]; }",
" if (element[0] === '/') { return result / element[1]; }", " if (element[0] === '/') { return result / element[1]; }",
" }, head);", " }, head);",
" }", " }",
"Value = digits:[0-9]+ { return parseInt(digits.join(''), 10); }", "Value = digits:[0-9]+ { return parseInt(digits.join(''), 10); }",
" / '(' expr:Expr ')' { return expr; }" " / '(' expr:Expr ')' { return expr; }"
].join("\n"), options); ].join("\n"), options);
// The "value" rule // The "value" rule
expect(parser).toParse("0", 0); expect(parser).toParse("0", 0);
@ -1528,10 +1528,10 @@ describe("generated parser behavior", function() {
// A ← a A? b // A ← a A? b
// B ← b B? c // B ← b B? c
let parser = peg.generate([ let parser = peg.generate([
"S = &(A 'c') a:'a'+ B:B !('a' / 'b' / 'c') { return a.join('') + B; }", "S = &(A 'c') a:'a'+ B:B !('a' / 'b' / 'c') { return a.join('') + B; }",
"A = a:'a' A:A? b:'b' { return [a, A, b].join(''); }", "A = a:'a' A:A? b:'b' { return [a, A, b].join(''); }",
"B = b:'b' B:B? c:'c' { return [b, B, c].join(''); }" "B = b:'b' B:B? c:'c' { return [b, B, c].join(''); }"
].join("\n"), options); ].join("\n"), options);
expect(parser).toParse("abc", "abc"); expect(parser).toParse("abc", "abc");
expect(parser).toParse("aaabbbccc", "aaabbbccc"); expect(parser).toParse("aaabbbccc", "aaabbbccc");
@ -1550,13 +1550,13 @@ describe("generated parser behavior", function() {
// N ← C / (!Begin !End Z) // N ← C / (!Begin !End Z)
// Z ← any single character // Z ← any single character
let parser = peg.generate([ let parser = peg.generate([
"C = begin:Begin ns:N* end:End { return begin + ns.join('') + end; }", "C = begin:Begin ns:N* end:End { return begin + ns.join('') + end; }",
"N = C", "N = C",
" / !Begin !End z:Z { return z; }", " / !Begin !End z:Z { return z; }",
"Z = .", "Z = .",
"Begin = '(*'", "Begin = '(*'",
"End = '*)'" "End = '*)'"
].join("\n"), options); ].join("\n"), options);
expect(parser).toParse("(**)", "(**)"); expect(parser).toParse("(**)", "(**)");
expect(parser).toParse("(*abc*)", "(*abc*)"); expect(parser).toParse("(*abc*)", "(*abc*)");

@ -22,17 +22,17 @@ describe("PEG.js grammar parser", function() {
let labeledMnop = { type: "labeled", label: "d", expression: literalMnop }; let labeledMnop = { type: "labeled", label: "d", expression: literalMnop };
let labeledSimpleNot = { type: "labeled", label: "a", expression: simpleNotAbcd }; let labeledSimpleNot = { type: "labeled", label: "a", expression: simpleNotAbcd };
let sequence = { let sequence = {
type: "sequence", type: "sequence",
elements: [literalAbcd, literalEfgh, literalIjkl] elements: [literalAbcd, literalEfgh, literalIjkl]
}; };
let sequence2 = { let sequence2 = {
type: "sequence", type: "sequence",
elements: [labeledAbcd, labeledEfgh] elements: [labeledAbcd, labeledEfgh]
}; };
let sequence4 = { let sequence4 = {
type: "sequence", type: "sequence",
elements: [labeledAbcd, labeledEfgh, labeledIjkl, labeledMnop] elements: [labeledAbcd, labeledEfgh, labeledIjkl, labeledMnop]
}; };
let groupLabeled = { type: "group", expression: labeledAbcd }; let groupLabeled = { type: "group", expression: labeledAbcd };
let groupSequence = { type: "group", expression: sequence }; let groupSequence = { type: "group", expression: sequence };
let actionAbcd = { type: "action", expression: literalAbcd, code: " code " }; let actionAbcd = { type: "action", expression: literalAbcd, code: " code " };
@ -41,17 +41,17 @@ describe("PEG.js grammar parser", function() {
let actionMnop = { type: "action", expression: literalMnop, code: " code " }; let actionMnop = { type: "action", expression: literalMnop, code: " code " };
let actionSequence = { type: "action", expression: sequence, code: " code " }; let actionSequence = { type: "action", expression: sequence, code: " code " };
let choice = { let choice = {
type: "choice", type: "choice",
alternatives: [literalAbcd, literalEfgh, literalIjkl] alternatives: [literalAbcd, literalEfgh, literalIjkl]
}; };
let choice2 = { let choice2 = {
type: "choice", type: "choice",
alternatives: [actionAbcd, actionEfgh] alternatives: [actionAbcd, actionEfgh]
}; };
let choice4 = { let choice4 = {
type: "choice", type: "choice",
alternatives: [actionAbcd, actionEfgh, actionIjkl, actionMnop] alternatives: [actionAbcd, actionEfgh, actionIjkl, actionMnop]
}; };
let named = { type: "named", name: "start rule", expression: literalAbcd }; let named = { type: "named", name: "start rule", expression: literalAbcd };
let ruleA = { type: "rule", name: "a", expression: literalAbcd }; let ruleA = { type: "rule", name: "a", expression: literalAbcd };
let ruleB = { type: "rule", name: "b", expression: literalEfgh }; let ruleB = { type: "rule", name: "b", expression: literalEfgh };
@ -98,10 +98,10 @@ describe("PEG.js grammar parser", function() {
let trivialGrammar = literalGrammar("abcd", false); let trivialGrammar = literalGrammar("abcd", false);
let twoRuleGrammar = { let twoRuleGrammar = {
type: "grammar", type: "grammar",
initializer: null, initializer: null,
rules: [ruleA, ruleB] rules: [ruleA, ruleB]
}; };
let stripLocation = (function() { let stripLocation = (function() {
function buildVisitor(functions) { function buildVisitor(functions) {

Loading…
Cancel
Save