diff --git a/lib/compiler/index.js b/lib/compiler/index.js index 40c05f3..d3edda9 100644 --- a/lib/compiler/index.js +++ b/lib/compiler/index.js @@ -19,16 +19,17 @@ var compiler = { */ passes: { check: { - reportMissingRules: require("./passes/report-missing-rules"), - reportLeftRecursion: require("./passes/report-left-recursion"), - reportInfiniteLoops: require("./passes/report-infinite-loops") + reportMissingRules: require("./passes/report-missing-rules"), + reportDuplicateRules: require("./passes/report-duplicate-rules"), + reportLeftRecursion: require("./passes/report-left-recursion"), + reportInfiniteLoops: require("./passes/report-infinite-loops") }, transform: { - removeProxyRules: require("./passes/remove-proxy-rules") + removeProxyRules: require("./passes/remove-proxy-rules") }, generate: { - generateBytecode: require("./passes/generate-bytecode"), - generateJS: require("./passes/generate-js") + generateBytecode: require("./passes/generate-bytecode"), + generateJS: require("./passes/generate-js") } }, diff --git a/lib/compiler/passes/report-duplicate-rules.js b/lib/compiler/passes/report-duplicate-rules.js new file mode 100644 index 0000000..44cfa27 --- /dev/null +++ b/lib/compiler/passes/report-duplicate-rules.js @@ -0,0 +1,26 @@ +"use strict"; + +var GrammarError = require("../../grammar-error"), + visitor = require("../visitor"); + +/* Checks that each rule is defined only once. */ +function reportDuplicateRules(ast) { + var rules = {}; + + var check = visitor.build({ + rule: function(node) { + if (rules.hasOwnProperty(node.name)) { + throw new GrammarError( + "Rule \"" + node.name + "\" is already defined.", + node.location + ); + } + + rules[node.name] = true; + } + }); + + check(ast); +} + +module.exports = reportDuplicateRules; diff --git a/package.json b/package.json index 3f5d20d..032326f 100644 --- a/package.json +++ b/package.json @@ -31,6 +31,7 @@ "lib/compiler/passes/report-left-recursion.js", "lib/compiler/passes/report-infinite-loops.js", "lib/compiler/passes/report-missing-rules.js", + "lib/compiler/passes/report-duplicate-rules.js", "lib/grammar-error.js", "lib/parser.js", "lib/peg.js", diff --git a/spec/index.html b/spec/index.html index db65963..d59581b 100644 --- a/spec/index.html +++ b/spec/index.html @@ -10,6 +10,7 @@ + diff --git a/spec/unit/compiler/passes/report-duplicate-rules.spec.js b/spec/unit/compiler/passes/report-duplicate-rules.spec.js new file mode 100644 index 0000000..a74554e --- /dev/null +++ b/spec/unit/compiler/passes/report-duplicate-rules.spec.js @@ -0,0 +1,20 @@ +/* global peg */ + +"use strict"; + +describe("compiler pass |reportDuplicateRules|", function() { + var pass = peg.compiler.passes.check.reportDuplicateRules; + + it("reports duplicate rules", function() { + expect(pass).toReportError([ + 'start = "a"', + 'start = "b"' + ].join('\n'), { + message: 'Rule "start" is already defined.', + location: { + start: { offset: 12, line: 2, column: 1 }, + end: { offset: 23, line: 2, column: 12 } + } + }); + }); +});