Specs cleanup: Simplify compiler passes specs
After 898a7b5a2d
the specs mostly tested
the visitor implementation, not actual code in the passes.
redux
parent
4ec9e6ba10
commit
850ddf5889
@ -1,140 +1,51 @@
|
|||||||
describe("compiler pass |removeProxyRules|", function() {
|
describe("compiler pass |removeProxyRules|", function() {
|
||||||
var pass = PEG.compiler.passes.transform.removeProxyRules;
|
var pass = PEG.compiler.passes.transform.removeProxyRules;
|
||||||
|
|
||||||
function proxyGrammar(rule) {
|
describe("when a proxy rule isn't listed in |allowedStartRules|", function() {
|
||||||
return [rule, 'proxy = proxied', 'proxied = "a"'].join("\n");
|
it("updates references and removes it", function() {
|
||||||
}
|
expect(pass).toChangeAST(
|
||||||
|
[
|
||||||
function expressionDetails(details) {
|
'start = proxy',
|
||||||
return {
|
'proxy = proxied',
|
||||||
rules: [
|
'proxied = "a"'
|
||||||
{ type: "rule", name: "start", expression: details },
|
].join("\n"),
|
||||||
{ type: "rule", name: "proxied" }
|
{ allowedStartRules: ["start"] },
|
||||||
]
|
{
|
||||||
};
|
rules: [
|
||||||
}
|
{
|
||||||
|
name: "start",
|
||||||
var defaultOptions = { allowedStartRules: ["start"] },
|
expression: { type: "rule_ref", name: "proxied" }
|
||||||
proxiedRefDetails = { type: "rule_ref", name: "proxied" },
|
},
|
||||||
simpleDetails = expressionDetails({ expression: proxiedRefDetails });
|
{ name: "proxied" }
|
||||||
|
]
|
||||||
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" }
|
|
||||||
]
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("removes proxy rule from a named", function() {
|
describe("when a proxy rule is listed in |allowedStartRules|", function() {
|
||||||
expect(pass).toChangeAST(
|
it("updates references but doesn't remove it", function() {
|
||||||
proxyGrammar('start "start" = proxy'),
|
expect(pass).toChangeAST(
|
||||||
defaultOptions,
|
[
|
||||||
simpleDetails
|
'start = proxy',
|
||||||
);
|
'proxy = proxied',
|
||||||
});
|
'proxied = "a"'
|
||||||
|
].join("\n"),
|
||||||
it("removes proxy rule from a choice", function() {
|
{ allowedStartRules: ["start", "proxy"] },
|
||||||
expect(pass).toChangeAST(
|
{
|
||||||
proxyGrammar('start = proxy / "a" / "b"'),
|
rules: [
|
||||||
defaultOptions,
|
{
|
||||||
expressionDetails({ alternatives: [proxiedRefDetails, {}, {}] })
|
name: "start",
|
||||||
);
|
expression: { type: "rule_ref", name: "proxied" }
|
||||||
expect(pass).toChangeAST(
|
},
|
||||||
proxyGrammar('start = "a" / "b" / proxy'),
|
{
|
||||||
defaultOptions,
|
name: "proxy",
|
||||||
expressionDetails({ alternatives: [{}, {}, proxiedRefDetails] })
|
expression: { type: "rule_ref", name: "proxied" }
|
||||||
);
|
},
|
||||||
});
|
{ name: "proxied" }
|
||||||
|
]
|
||||||
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" }
|
|
||||||
]
|
|
||||||
}
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -1,96 +1,29 @@
|
|||||||
describe("compiler pass |reportLeftRecursion|", function() {
|
describe("compiler pass |reportLeftRecursion|", function() {
|
||||||
var pass = PEG.compiler.passes.check.reportLeftRecursion;
|
var pass = PEG.compiler.passes.check.reportLeftRecursion;
|
||||||
|
|
||||||
beforeEach(function() {
|
it("reports direct left recursion", function() {
|
||||||
this.addMatchers({
|
expect(pass).toReportError('start = start', {
|
||||||
toReportLeftRecursionIn: function(grammar) {
|
message: 'Left recursion detected for rule \"start\".'
|
||||||
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 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() {
|
it("reports indirect left recursion", function() {
|
||||||
expect(pass).toReportLeftRecursionIn([
|
expect(pass).toReportError([
|
||||||
'start = stop',
|
'start = stop',
|
||||||
'stop = start'
|
'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() {
|
describe("compiler pass |reportMissingRules|", function() {
|
||||||
var pass = PEG.compiler.passes.check.reportMissingRules;
|
var pass = PEG.compiler.passes.check.reportMissingRules;
|
||||||
|
|
||||||
beforeEach(function() {
|
it("reports missing rules", function() {
|
||||||
this.addMatchers({
|
expect(pass).toReportError('start = missing', {
|
||||||
toReportMissingRuleIn: function(grammar) {
|
message: 'Referenced rule "missing" does not exist.'
|
||||||
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 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…
Reference in New Issue