Extract the |matchesEmpty| visitor from the |reportLeftRecursion| pass
Beside the recursion detector, the visitor will also be used by infinite loop detector. Note the newly created |asts.matchesEmpty| function re-creates the visitor each time it is called, which makes it slower than necessary. This could have been worked around in various ways but I chose to defer that optimization because real-world performance impact is small.
This commit is contained in:
parent
03a391e874
commit
95ce20ed92
2
Makefile
2
Makefile
|
@ -10,8 +10,8 @@ MODULES = utils/arrays \
|
||||||
utils/classes \
|
utils/classes \
|
||||||
grammar-error \
|
grammar-error \
|
||||||
parser \
|
parser \
|
||||||
compiler/asts \
|
|
||||||
compiler/visitor \
|
compiler/visitor \
|
||||||
|
compiler/asts \
|
||||||
compiler/opcodes \
|
compiler/opcodes \
|
||||||
compiler/javascript \
|
compiler/javascript \
|
||||||
compiler/passes/generate-bytecode \
|
compiler/passes/generate-bytecode \
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
var arrays = require("../utils/arrays");
|
var arrays = require("../utils/arrays"),
|
||||||
|
visitor = require("./visitor");
|
||||||
|
|
||||||
/* AST utilities. */
|
/* AST utilities. */
|
||||||
var asts = {
|
var asts = {
|
||||||
|
@ -8,6 +9,52 @@ var asts = {
|
||||||
|
|
||||||
indexOfRule: function(ast, name) {
|
indexOfRule: function(ast, name) {
|
||||||
return arrays.indexOf(ast.rules, function(r) { return r.name === name; });
|
return arrays.indexOf(ast.rules, function(r) { return r.name === name; });
|
||||||
|
},
|
||||||
|
|
||||||
|
matchesEmpty: function(ast, node) {
|
||||||
|
function matchesTrue() { return true; }
|
||||||
|
function matchesFalse() { return false; }
|
||||||
|
|
||||||
|
function matchesExpression(node) {
|
||||||
|
return matches(node.expression);
|
||||||
|
}
|
||||||
|
|
||||||
|
var matches = visitor.build({
|
||||||
|
rule: matchesExpression,
|
||||||
|
|
||||||
|
choice: function(node) {
|
||||||
|
return arrays.some(node.alternatives, matches);
|
||||||
|
},
|
||||||
|
|
||||||
|
action: matchesExpression,
|
||||||
|
|
||||||
|
sequence: function(node) {
|
||||||
|
return arrays.every(node.elements, matches);
|
||||||
|
},
|
||||||
|
|
||||||
|
labeled: matchesExpression,
|
||||||
|
text: matchesExpression,
|
||||||
|
simple_and: matchesTrue,
|
||||||
|
simple_not: matchesTrue,
|
||||||
|
optional: matchesTrue,
|
||||||
|
zero_or_more: matchesTrue,
|
||||||
|
one_or_more: matchesExpression,
|
||||||
|
semantic_and: matchesTrue,
|
||||||
|
semantic_not: matchesTrue,
|
||||||
|
|
||||||
|
rule_ref: function(node) {
|
||||||
|
return matches(asts.findRule(ast, node.name));
|
||||||
|
},
|
||||||
|
|
||||||
|
literal: function(node) {
|
||||||
|
return node.value === "";
|
||||||
|
},
|
||||||
|
|
||||||
|
"class": matchesFalse,
|
||||||
|
any: matchesFalse
|
||||||
|
});
|
||||||
|
|
||||||
|
return matches(node);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -16,48 +16,6 @@ var arrays = require("../../utils/arrays"),
|
||||||
* it can lead to left recursion.
|
* it can lead to left recursion.
|
||||||
*/
|
*/
|
||||||
function reportLeftRecursion(ast) {
|
function reportLeftRecursion(ast) {
|
||||||
function matchesEmptyTrue() { return true; }
|
|
||||||
function matchesEmptyFalse() { return false; }
|
|
||||||
|
|
||||||
function matchesEmptyExpression(node) {
|
|
||||||
return matchesEmpty(node.expression);
|
|
||||||
}
|
|
||||||
|
|
||||||
var matchesEmpty = visitor.build({
|
|
||||||
rule: matchesEmptyExpression,
|
|
||||||
|
|
||||||
choice: function(node) {
|
|
||||||
return arrays.some(node.alternatives, matchesEmpty);
|
|
||||||
},
|
|
||||||
|
|
||||||
action: matchesEmptyExpression,
|
|
||||||
|
|
||||||
sequence: function(node) {
|
|
||||||
return arrays.every(node.elements, matchesEmpty);
|
|
||||||
},
|
|
||||||
|
|
||||||
labeled: matchesEmptyExpression,
|
|
||||||
text: matchesEmptyExpression,
|
|
||||||
simple_and: matchesEmptyTrue,
|
|
||||||
simple_not: matchesEmptyTrue,
|
|
||||||
optional: matchesEmptyTrue,
|
|
||||||
zero_or_more: matchesEmptyTrue,
|
|
||||||
one_or_more: matchesEmptyExpression,
|
|
||||||
semantic_and: matchesEmptyTrue,
|
|
||||||
semantic_not: matchesEmptyTrue,
|
|
||||||
|
|
||||||
rule_ref: function(node) {
|
|
||||||
return matchesEmpty(asts.findRule(ast, node.name));
|
|
||||||
},
|
|
||||||
|
|
||||||
literal: function(node) {
|
|
||||||
return node.value === "";
|
|
||||||
},
|
|
||||||
|
|
||||||
"class": matchesEmptyFalse,
|
|
||||||
any: matchesEmptyFalse
|
|
||||||
});
|
|
||||||
|
|
||||||
var check = visitor.build({
|
var check = visitor.build({
|
||||||
rule: function(node, visitedRules) {
|
rule: function(node, visitedRules) {
|
||||||
check(node.expression, visitedRules.concat(node.name));
|
check(node.expression, visitedRules.concat(node.name));
|
||||||
|
@ -69,7 +27,7 @@ function reportLeftRecursion(ast) {
|
||||||
check(element, visitedRules);
|
check(element, visitedRules);
|
||||||
}
|
}
|
||||||
|
|
||||||
return matchesEmpty(element);
|
return asts.matchesEmpty(ast, element);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue