parent
2a889535bd
commit
eb67cbedb4
@ -0,0 +1,54 @@
|
||||
"use strict";
|
||||
|
||||
var GrammarError = require("../../grammar-error"),
|
||||
arrays = require("../../utils/arrays"),
|
||||
objects = require("../../utils/objects"),
|
||||
visitor = require("../visitor");
|
||||
|
||||
/* Checks that each label is defined only once within each scope. */
|
||||
function reportDuplicateLabels(ast) {
|
||||
function checkExpressionWithClonedEnv(node, env) {
|
||||
check(node.expression, objects.clone(env));
|
||||
}
|
||||
|
||||
var check = visitor.build({
|
||||
rule: function(node) {
|
||||
check(node.expression, { });
|
||||
},
|
||||
|
||||
choice: function(node, env) {
|
||||
arrays.each(node.alternatives, function(alternative) {
|
||||
check(alternative, objects.clone(env));
|
||||
});
|
||||
},
|
||||
|
||||
action: checkExpressionWithClonedEnv,
|
||||
|
||||
labeled: function(node, env) {
|
||||
if (env.hasOwnProperty(node.label)) {
|
||||
throw new GrammarError(
|
||||
"Label \"" + node.label + "\" is already defined "
|
||||
+ "at line " + env[node.label].start.line + ", "
|
||||
+ "column " + env[node.label].start.column + ".",
|
||||
node.location
|
||||
);
|
||||
}
|
||||
|
||||
check(node.expression, env);
|
||||
|
||||
env[node.label] = node.location;
|
||||
},
|
||||
|
||||
text: checkExpressionWithClonedEnv,
|
||||
simple_and: checkExpressionWithClonedEnv,
|
||||
simple_not: checkExpressionWithClonedEnv,
|
||||
optional: checkExpressionWithClonedEnv,
|
||||
zero_or_more: checkExpressionWithClonedEnv,
|
||||
one_or_more: checkExpressionWithClonedEnv,
|
||||
group: checkExpressionWithClonedEnv
|
||||
});
|
||||
|
||||
check(ast);
|
||||
}
|
||||
|
||||
module.exports = reportDuplicateLabels;
|
@ -0,0 +1,59 @@
|
||||
/* global peg */
|
||||
|
||||
"use strict";
|
||||
|
||||
describe("compiler pass |reportDuplicateLabels|", function() {
|
||||
var pass = peg.compiler.passes.check.reportDuplicateLabels;
|
||||
|
||||
describe("in a sequence", function() {
|
||||
it("reports labels duplicate with labels of preceding elements", function() {
|
||||
expect(pass).toReportError('start = a:"a" a:"a"', {
|
||||
message: 'Label "a" is already defined at line 1, column 9.',
|
||||
location: {
|
||||
start: { offset: 14, line: 1, column: 15 },
|
||||
end: { offset: 19, line: 1, column: 20 }
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
it("doesn't report labels duplicate with labels in subexpressions", function() {
|
||||
expect(pass).not.toReportError('start = ("a" / a:"a" / "a") a:"a"');
|
||||
expect(pass).not.toReportError('start = (a:"a" { }) a:"a"');
|
||||
expect(pass).not.toReportError('start = ("a" a:"a" "a") a:"a"');
|
||||
expect(pass).not.toReportError('start = b:(a:"a") a:"a"');
|
||||
expect(pass).not.toReportError('start = $(a:"a") a:"a"');
|
||||
expect(pass).not.toReportError('start = &(a:"a") a:"a"');
|
||||
expect(pass).not.toReportError('start = !(a:"a") a:"a"');
|
||||
expect(pass).not.toReportError('start = (a:"a")? a:"a"');
|
||||
expect(pass).not.toReportError('start = (a:"a")* a:"a"');
|
||||
expect(pass).not.toReportError('start = (a:"a")+ a:"a"');
|
||||
expect(pass).not.toReportError('start = (a:"a") a:"a"');
|
||||
});
|
||||
});
|
||||
|
||||
describe("in a choice", function() {
|
||||
it("doesn't report labels duplicate with labels of preceding alternatives", function() {
|
||||
expect(pass).not.toReportError('start = a:"a" / a:"a"');
|
||||
});
|
||||
});
|
||||
|
||||
describe("in outer sequence", function() {
|
||||
it("reports labels duplicate with labels of preceding elements", function() {
|
||||
expect(pass).toReportError('start = a:"a" (a:"a")', {
|
||||
message: 'Label "a" is already defined at line 1, column 9.',
|
||||
location: {
|
||||
start: { offset: 15, line: 1, column: 16 },
|
||||
end: { offset: 20, line: 1, column: 21 }
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
it("doesn't report labels duplicate with the label of the current element", function() {
|
||||
expect(pass).not.toReportError('start = a:(a:"a")');
|
||||
});
|
||||
|
||||
it("doesn't report labels duplicate with labels of following elements", function() {
|
||||
expect(pass).not.toReportError('start = (a:"a") a:"a"');
|
||||
});
|
||||
});
|
||||
});
|
Loading…
Reference in New Issue