-
Notifications
You must be signed in to change notification settings - Fork 420
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Report duplicate rule definitions as errors
- Loading branch information
Showing
5 changed files
with
55 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 } | ||
} | ||
}); | ||
}); | ||
}); |
eb5875b
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think, that message will be more informative if it contains location of the first occurrence of the rule.
eb5875b
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Mingun Technically, the problem is not the original definition, but the redefinition, so I think it makes sense to point to it rather than the original definition.
Usability-wise, it would probably be best to point to all the duplicate definitions. But this would require either support for multiple locations per error (so one error can point to all the duplicate definitions) or support for producing multiple errors in
peg.generate
(so each error can point to one duplicate definition). Both solutions add complexity which I don’t want to introduce to PEG.js — at least not yet.eb5875b
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not always the second definition of the rule will be erratic. The error can just contain in the first rule. To specify several places there is no need since all the same all rules, since the second, will generate this error
eb5875b
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Your response is hard to parse, but I’ll try to reply anyway.
One can’t know which instance of a duplicate rule is the one the user wants to be pointed at. It’s probably the one he/she will want to change in response to the error.
If we hypothesize that users write grammars mostly sequentially, it makes sense to point to the last duplicate rule because that’s the one the user probably added last.
One can also look at things from the technical side. The grammar is processed from the beginning to the end, like pretty much any other source code. The error is triggered by the second instance of the rule (not the first, third, fourth, etc.), so this is where it should be reported.
I sided to the technical view because I find it natural, because I’m convinced it will make sense to most users, and because I don’t think the sequential hypothesis really holds. It was also easy to implement. I don’t see any arguments whatsoever for pointing to the first instance. Nothing you wrote so far has provided one.
This example at the TypeScript playground shows what I consider an ideal report about a duplicate identifier.
eb5875b
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't say that the error shall arise on the first rule. I say that the good form is include in error message location of the first rule. Many compilers does this
eb5875b
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@dmajda, I think what @Mingun means is that this:
is more informative then this:
This does indeed help track down the duplicate rules more easily, but only if you are using PEG.js through the console or like the online editor.
If you have the parser and compiler hooked through a try/catch (like I do ;P) then most likely the thrown messages are ran through a RegExp to find out what type of error it is and then the location field of the thrown error is used, in which case using the approach in this commit is easier.
eb5875b
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Mingun I get it now, sorry for misunderstanding. (Re-reading your original comment, it looks like my fault.)
Embedding a location of the original definition into the error message feels a bit hacky, but I agree it is useful, so I implemented it. I filed #430 to track implementation of a more systematic solution at some point in the future.