Fix too eager proxy rules removal

Fixes GH-137.
redux
David Majda 12 years ago
parent 5d00815b41
commit 3981433984

@ -3,7 +3,7 @@ var utils = require("../../utils");
/* /*
* Removes proxy rules -- that is, rules that only delegate to other rule. * Removes proxy rules -- that is, rules that only delegate to other rule.
*/ */
module.exports = function(ast) { module.exports = function(ast, options) {
function isProxyRule(node) { function isProxyRule(node) {
return node.type === "rule" && node.expression.type === "rule_ref"; return node.type === "rule" && node.expression.type === "rule_ref";
} }
@ -55,15 +55,17 @@ module.exports = function(ast) {
replace(ast, from, to); replace(ast, from, to);
} }
var indices = []; var indices = [],
allowedStartRules = options.allowedStartRules !== undefined
? options.allowedStartRules
: [ast.startRule];
utils.each(ast.rules, function(rule, i) { utils.each(ast.rules, function(rule, i) {
if (isProxyRule(rule)) { if (isProxyRule(rule)) {
replaceRuleRefs(ast, rule.name, rule.expression.name); replaceRuleRefs(ast, rule.name, rule.expression.name);
if (rule.name === ast.startRule) { if (!utils.contains(allowedStartRules, rule.name)) {
ast.startRule = rule.expression.name; indices.push(i);
} }
indices.push(i);
} }
}); });

@ -19,8 +19,8 @@ describe("compiler pass |removeProxyRules|", function() {
it("removes proxy rule from a rule", function() { it("removes proxy rule from a rule", function() {
expect(pass).toChangeAST(proxyGrammar('start = proxy'), { expect(pass).toChangeAST(proxyGrammar('start = proxy'), {
startRule: "proxied", rules: [
rules: [ { type: "rule", name: "start", expression: proxiedRefDetails },
{ type: "rule", name: "proxied" } { type: "rule", name: "proxied" }
] ]
}); });
@ -86,4 +86,17 @@ describe("compiler pass |removeProxyRules|", function() {
it("removes proxy rule from a one or more", function() { it("removes proxy rule from a one or more", function() {
expect(pass).toChangeAST(proxyGrammar('start = proxy+'), simpleDetails); expect(pass).toChangeAST(proxyGrammar('start = proxy+'), 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" }
]
}
);
});
}); });

@ -4,7 +4,7 @@ if (typeof module !== "undefined") {
beforeEach(function() { beforeEach(function() {
this.addMatchers({ this.addMatchers({
toChangeAST: function(grammar, details) { toChangeAST: function(grammar) {
function matchDetails(value, details) { function matchDetails(value, details) {
function isArray(value) { function isArray(value) {
return Object.prototype.toString.apply(value) === "[object Array]"; return Object.prototype.toString.apply(value) === "[object Array]";
@ -40,12 +40,15 @@ beforeEach(function() {
} }
} }
var ast = PEG.parser.parse(grammar); var options = arguments.length > 2 ? arguments[1] : {},
details = arguments[arguments.length - 1],
ast = PEG.parser.parse(grammar);
this.actual(ast); this.actual(ast, options);
this.message = function() { this.message = function() {
return "Expected the pass " return "Expected the pass "
+ "with options " + jasmine.pp(options) + " "
+ (this.isNot ? "not " : "") + (this.isNot ? "not " : "")
+ "to change the AST " + jasmine.pp(ast) + " " + "to change the AST " + jasmine.pp(ast) + " "
+ "to match " + jasmine.pp(details) + ", " + "to match " + jasmine.pp(details) + ", "

Loading…
Cancel
Save