var arrays = require("../../utils/arrays"), GrammarError = require("../../grammar-error"), asts = require("../asts"), visitor = require("../visitor"); /* Checks that no left recursion is present. */ function reportLeftRecursion(ast) { function nop() {} function checkExpression(node, appliedRules) { check(node.expression, appliedRules); } function checkSubnodes(propertyName) { return function(node, appliedRules) { arrays.each(node[propertyName], function(subnode) { check(subnode, appliedRules); }); }; } var check = visitor.build({ grammar: checkSubnodes("rules"), rule: function(node, appliedRules) { check(node.expression, appliedRules.concat(node.name)); }, named: checkExpression, choice: checkSubnodes("alternatives"), action: checkExpression, sequence: function(node, appliedRules) { if (node.elements.length > 0) { check(node.elements[0], appliedRules); } }, labeled: checkExpression, text: checkExpression, simple_and: checkExpression, simple_not: checkExpression, semantic_and: nop, semantic_not: nop, optional: checkExpression, zero_or_more: checkExpression, one_or_more: checkExpression, rule_ref: function(node, appliedRules) { if (arrays.contains(appliedRules, node.name)) { throw new GrammarError( "Left recursion detected for rule \"" + node.name + "\"." ); } check(asts.findRule(ast, node.name), appliedRules); }, literal: nop, "class": nop, any: nop }); check(ast, []); } module.exports = reportLeftRecursion;