diff --git a/lib/compiler/index.js b/lib/compiler/index.js index 16bd832..61ea4dc 100644 --- a/lib/compiler/index.js +++ b/lib/compiler/index.js @@ -6,6 +6,7 @@ const generateJS = require( "./passes/generate-js" ); const removeProxyRules = require( "./passes/remove-proxy-rules" ); const reportDuplicateLabels = require( "./passes/report-duplicate-labels" ); const reportDuplicateRules = require( "./passes/report-duplicate-rules" ); +const reportUnusedRules = require( "./passes/report-unused-rules" ); const reportInfiniteRecursion = require( "./passes/report-infinite-recursion" ); const reportInfiniteRepetition = require( "./passes/report-infinite-repetition" ); const reportUndefinedRules = require( "./passes/report-undefined-rules" ); @@ -37,6 +38,7 @@ const compiler = { check: { reportUndefinedRules: reportUndefinedRules, reportDuplicateRules: reportDuplicateRules, + reportUnusedRules: reportUnusedRules, reportDuplicateLabels: reportDuplicateLabels, reportInfiniteRecursion: reportInfiniteRecursion, reportInfiniteRepetition: reportInfiniteRepetition diff --git a/lib/compiler/passes/report-unused-rules.js b/lib/compiler/passes/report-unused-rules.js new file mode 100644 index 0000000..9341c83 --- /dev/null +++ b/lib/compiler/passes/report-unused-rules.js @@ -0,0 +1,31 @@ +"use strict"; + +// Checks that all rules are used. +function reportUnusedRules( ast, session, options ) { + + const used = {}; + function yes( node ) { + + used[ node.name || node ] = true; + + } + + options.allowedStartRules.forEach( yes ); + session.buildVisitor( { rule_ref: yes } )( ast ); + + ast.rules.forEach( rule => { + + if ( used[ rule.name ] !== true ) { + + session.warn( + `Rule "${ rule.name }" is not referenced.`, + rule.location + ); + + } + + } ); + +} + +module.exports = reportUnusedRules; diff --git a/test/spec/unit/compiler/passes/report-unused-rules.spec.js b/test/spec/unit/compiler/passes/report-unused-rules.spec.js new file mode 100644 index 0000000..52b7d9b --- /dev/null +++ b/test/spec/unit/compiler/passes/report-unused-rules.spec.js @@ -0,0 +1,64 @@ +"use strict"; + +const chai = require( "chai" ); +const helpers = require( "./helpers" ); +const pass = require( "pegjs-dev" ).compiler.passes.check.reportUnusedRules; + +chai.use( helpers ); + +const expect = chai.expect; + +describe( "compiler pass |reportUnusedRules|", function () { + + it( "should report rules that are not referenced", function () { + + expect( pass ).to.reportWarning( + ` + start = . + unused = . + `, + `Rule "unused" is not referenced.` + ); + + expect( pass ).to.reportWarning( + ` + start = . + unused = . + used = . + `, + [ + `Rule "used" is not referenced.`, + `Rule "unused" is not referenced.` + ] + ); + + } ); + + it( "does not report rules that are referenced", function () { + + expect( pass ).not.to.reportWarning( `start = .` ); + + expect( pass ).not.to.reportWarning( ` + start = used + used = . + ` ); + + } ); + + it( "does not report any rules that the generated parser starts parsing from", function () { + + expect( pass ).not.to.reportWarning( + ` + a = "x" + b = a + c = .+ + `, + null, + { + allowedStartRules: [ "b", "c" ] + } + ); + + } ); + +} );