Specs cleanup: Simplify compiler passes specs

After 898a7b5a2d the specs mostly tested
the visitor implementation, not actual code in the passes.
redux
David Majda 10 years ago
parent 4ec9e6ba10
commit 850ddf5889

@ -54,6 +54,57 @@ beforeEach(function() {
};
return matchDetails(ast, details);
},
toReportError: function(grammar, details) {
var ast = PEG.parser.parse(grammar);
try {
this.actual(ast);
this.message = function() {
return "Expected the pass to report an error"
+ (details ? " with details " + jasmine.pp(details) : "") + ", "
+ "for grammar " + jasmine.pp(grammar) + ", "
+ "but it didn't.";
};
return false;
} catch (e) {
/*
* Should be at the top level but then JSHint complains about bad for
* in variable.
*/
var key;
if (this.isNot) {
this.message = function() {
return "Expected the pass not to report an error"
+ "for grammar " + jasmine.pp(grammar) + ", "
+ "but it did.";
};
} else {
if (details) {
for (key in details) {
if (details.hasOwnProperty(key)) {
if (!this.env.equals_(e[key], details[key])) {
this.message = function() {
return "Expected the pass to report an error"
+ (details ? " with details " + jasmine.pp(details) : "") + ", "
+ "for grammar " + jasmine.pp(grammar) + ", "
+ "but " + jasmine.pp(key) + " "
+ "is " + jasmine.pp(e[key]) + ".";
};
return false;
}
}
}
}
}
return true;
}
}
});
});

@ -1,140 +1,51 @@
describe("compiler pass |removeProxyRules|", function() {
var pass = PEG.compiler.passes.transform.removeProxyRules;
function proxyGrammar(rule) {
return [rule, 'proxy = proxied', 'proxied = "a"'].join("\n");
}
function expressionDetails(details) {
return {
rules: [
{ type: "rule", name: "start", expression: details },
{ type: "rule", name: "proxied" }
]
};
}
var defaultOptions = { allowedStartRules: ["start"] },
proxiedRefDetails = { type: "rule_ref", name: "proxied" },
simpleDetails = expressionDetails({ expression: proxiedRefDetails });
it("removes proxy rule from a rule", function() {
expect(pass).toChangeAST(proxyGrammar('start = proxy'), defaultOptions, {
rules: [
{ type: "rule", name: "start", expression: proxiedRefDetails },
{ type: "rule", name: "proxied" }
]
describe("when a proxy rule isn't listed in |allowedStartRules|", function() {
it("updates references and removes it", function() {
expect(pass).toChangeAST(
[
'start = proxy',
'proxy = proxied',
'proxied = "a"'
].join("\n"),
{ allowedStartRules: ["start"] },
{
rules: [
{
name: "start",
expression: { type: "rule_ref", name: "proxied" }
},
{ name: "proxied" }
]
}
);
});
});
it("removes proxy rule from a named", function() {
expect(pass).toChangeAST(
proxyGrammar('start "start" = proxy'),
defaultOptions,
simpleDetails
);
});
it("removes proxy rule from a choice", function() {
expect(pass).toChangeAST(
proxyGrammar('start = proxy / "a" / "b"'),
defaultOptions,
expressionDetails({ alternatives: [proxiedRefDetails, {}, {}] })
);
expect(pass).toChangeAST(
proxyGrammar('start = "a" / "b" / proxy'),
defaultOptions,
expressionDetails({ alternatives: [{}, {}, proxiedRefDetails] })
);
});
it("removes proxy rule from an action", function() {
expect(pass).toChangeAST(
proxyGrammar('start = proxy { }'),
defaultOptions,
simpleDetails
);
});
it("removes proxy rule from a sequence", function() {
expect(pass).toChangeAST(
proxyGrammar('start = proxy "a" "b"'),
defaultOptions,
expressionDetails({ elements: [proxiedRefDetails, {}, {}] })
);
expect(pass).toChangeAST(
proxyGrammar('start = "a" "b" proxy'),
defaultOptions,
expressionDetails({ elements: [{}, {}, proxiedRefDetails] })
);
});
it("removes proxy rule from a labeled", function() {
expect(pass).toChangeAST(
proxyGrammar('start = label:proxy'),
defaultOptions,
simpleDetails
);
});
it("removes proxy rule from a text", function() {
expect(pass).toChangeAST(
proxyGrammar('start = $proxy'),
defaultOptions,
simpleDetails
);
});
it("removes proxy rule from a simple and", function() {
expect(pass).toChangeAST(
proxyGrammar('start = &proxy'),
defaultOptions,
simpleDetails
);
});
it("removes proxy rule from a simple not", function() {
expect(pass).toChangeAST(
proxyGrammar('start = &proxy'),
defaultOptions,
simpleDetails
);
});
it("removes proxy rule from an optional", function() {
expect(pass).toChangeAST(
proxyGrammar('start = proxy?'),
defaultOptions,
simpleDetails
);
});
it("removes proxy rule from a zero or more", function() {
expect(pass).toChangeAST(
proxyGrammar('start = proxy*'),
defaultOptions,
simpleDetails
);
});
it("removes proxy rule from a one or more", function() {
expect(pass).toChangeAST(
proxyGrammar('start = proxy+'),
defaultOptions,
simpleDetails
);
});
it("doesn't remove a proxy rule listed in |allowedStartRules|", function() {
expect(pass).toChangeAST(
proxyGrammar('start = proxy'),
{ allowedStartRules: ["proxy"] },
{
rules: [
{ name: "proxy" },
{ name: "proxied" }
]
}
);
describe("when a proxy rule is listed in |allowedStartRules|", function() {
it("updates references but doesn't remove it", function() {
expect(pass).toChangeAST(
[
'start = proxy',
'proxy = proxied',
'proxied = "a"'
].join("\n"),
{ allowedStartRules: ["start", "proxy"] },
{
rules: [
{
name: "start",
expression: { type: "rule_ref", name: "proxied" }
},
{
name: "proxy",
expression: { type: "rule_ref", name: "proxied" }
},
{ name: "proxied" }
]
}
);
});
});
});

@ -1,96 +1,29 @@
describe("compiler pass |reportLeftRecursion|", function() {
var pass = PEG.compiler.passes.check.reportLeftRecursion;
beforeEach(function() {
this.addMatchers({
toReportLeftRecursionIn: function(grammar) {
var ast = PEG.parser.parse(grammar);
try {
this.actual(ast);
this.message = function() {
return "Expected the pass to report left recursion for grammar "
+ jasmine.pp(grammar) + ", "
+ "but it didn't.";
};
return false;
} catch (e) {
if (this.isNot) {
this.message = function() {
return "Expected the pass not to report left recursion for grammar "
+ jasmine.pp(grammar) + ", "
+ "but it did.";
};
} else {
this.message = function() {
return "Expected the pass to report left recursion for grammar "
+ jasmine.pp(grammar) + ", "
+ "but it reported an error with message "
+ jasmine.pp(e.message) + ".";
};
}
return e.message === 'Left recursion detected for rule \"start\".';
}
}
it("reports direct left recursion", function() {
expect(pass).toReportError('start = start', {
message: 'Left recursion detected for rule \"start\".'
});
});
it("reports left recursion inside a rule", function() {
expect(pass).toReportLeftRecursionIn('start = start');
});
it("reports left recursion inside a named", function() {
expect(pass).toReportLeftRecursionIn('start "start" = start');
});
it("reports left recursion inside a choice", function() {
expect(pass).toReportLeftRecursionIn('start = start / "a" / "b"');
expect(pass).toReportLeftRecursionIn('start = "a" / "b" / start');
});
it("reports left recursion inside an action", function() {
expect(pass).toReportLeftRecursionIn('start = start { }');
});
it("reports left recursion inside a sequence", function() {
expect(pass).toReportLeftRecursionIn('start = start "a" "b"');
});
it("reports left recursion inside a labeled", function() {
expect(pass).toReportLeftRecursionIn('start = label:start');
});
it("reports left recursion inside a text", function() {
expect(pass).toReportLeftRecursionIn('start = $start');
});
it("reports left recursion inside a simple and", function() {
expect(pass).toReportLeftRecursionIn('start = &start');
});
it("reports left recursion inside a simple not", function() {
expect(pass).toReportLeftRecursionIn('start = &start');
});
it("reports left recursion inside an optional", function() {
expect(pass).toReportLeftRecursionIn('start = start?');
});
it("reports left recursion inside a zero or more", function() {
expect(pass).toReportLeftRecursionIn('start = start*');
});
it("reports left recursion inside a one or more", function() {
expect(pass).toReportLeftRecursionIn('start = start+');
});
it("reports indirect left recursion", function() {
expect(pass).toReportLeftRecursionIn([
expect(pass).toReportError([
'start = stop',
'stop = start'
].join("\n"));
].join("\n"), {
message: 'Left recursion detected for rule \"start\".'
});
});
describe("in sequences", function() {
it("reports left recursion only for the first element", function() {
expect(pass).toReportError('start = start "a" "b"', {
message: 'Left recursion detected for rule \"start\".'
});
expect(pass).not.toReportError('start = "a" start "b"');
expect(pass).not.toReportError('start = "a" "b" start');
});
});
});

@ -1,90 +1,9 @@
describe("compiler pass |reportMissingRules|", function() {
var pass = PEG.compiler.passes.check.reportMissingRules;
beforeEach(function() {
this.addMatchers({
toReportMissingRuleIn: function(grammar) {
var ast = PEG.parser.parse(grammar);
try {
this.actual(ast);
this.message = function() {
return "Expected the pass to report a missing rule for grammar "
+ jasmine.pp(grammar) + ", "
+ "but it didn't.";
};
return false;
} catch (e) {
if (this.isNot) {
this.message = function() {
return "Expected the pass not to report a missing rule for grammar "
+ jasmine.pp(grammar) + ", "
+ "but it did.";
};
} else {
this.message = function() {
return "Expected the pass to report a missing rule for grammar "
+ jasmine.pp(grammar) + ", "
+ "but it reported an error with message "
+ jasmine.pp(e.message) + ".";
};
}
return e.message === 'Referenced rule "missing" does not exist.';
}
}
it("reports missing rules", function() {
expect(pass).toReportError('start = missing', {
message: 'Referenced rule "missing" does not exist.'
});
});
it("reports missing rule referenced from a rule", function() {
expect(pass).toReportMissingRuleIn('start = missing');
});
it("reports missing rule referenced from a named", function() {
expect(pass).toReportMissingRuleIn('start "start" = missing');
});
it("reports missing rule referenced from a choice", function() {
expect(pass).toReportMissingRuleIn('start = missing / "a" / "b"');
expect(pass).toReportMissingRuleIn('start = "a" / "b" / missing');
});
it("reports missing rule referenced from an action", function() {
expect(pass).toReportMissingRuleIn('start = missing { }');
});
it("reports missing rule referenced from a sequence", function() {
expect(pass).toReportMissingRuleIn('start = missing "a" "b"');
expect(pass).toReportMissingRuleIn('start = "a" "b" missing');
});
it("reports missing rule referenced from a labeled", function() {
expect(pass).toReportMissingRuleIn('start = label:missing');
});
it("reports missing rule referenced from a text", function() {
expect(pass).toReportMissingRuleIn('start = $missing');
});
it("reports missing rule referenced from a simple and", function() {
expect(pass).toReportMissingRuleIn('start = &missing');
});
it("reports missing rule referenced from a simple not", function() {
expect(pass).toReportMissingRuleIn('start = &missing');
});
it("reports missing rule referenced from an optional", function() {
expect(pass).toReportMissingRuleIn('start = missing?');
});
it("reports missing rule referenced from a zero or more", function() {
expect(pass).toReportMissingRuleIn('start = missing*');
});
it("reports missing rule referenced from a one or more", function() {
expect(pass).toReportMissingRuleIn('start = missing+');
});
});

Loading…
Cancel
Save