You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
pegjs/test/compiler-test.js

220 lines
5.4 KiB
JavaScript

(function() {
module("PEG.compiler");
function testWithVaryingTrackLineAndColumn(name, callback) {
test(
name + " (with trackLineAndColumn: false) ",
function() { callback({ trackLineAndColumn: false }); }
);
test(
name + " (with trackLineAndColumn: true) ",
function() { callback({ trackLineAndColumn: true }); }
);
}
testWithVaryingTrackLineAndColumn("indempotence", function(options) {
var parser1 = PEG.buildParser('start = "abcd"', options);
var parser2 = PEG.buildParser('start = "abcd"', options);
strictEqual(parser1.toSource(), parser2.toSource());
});
testWithVaryingTrackLineAndColumn("error details", function(options) {
var literalParser = PEG.buildParser('start = "abcd"', options);
doesNotParseWithDetails(
literalParser,
"",
["\"abcd\""],
null,
'Expected "abcd" but end of input found.'
);
doesNotParseWithDetails(
literalParser,
"efgh",
["\"abcd\""],
"e",
'Expected "abcd" but "e" found.'
);
doesNotParseWithDetails(
literalParser,
"abcde",
[],
"e",
'Expected end of input but "e" found.'
);
var classParser = PEG.buildParser('start = [a-d]', options);
doesNotParseWithDetails(
classParser,
"",
["[a-d]"],
null,
'Expected [a-d] but end of input found.'
);
var negativeClassParser = PEG.buildParser('start = [^a-d]', options);
doesNotParseWithDetails(
negativeClassParser,
"",
["[^a-d]"],
null,
'Expected [^a-d] but end of input found.'
);
var anyParser = PEG.buildParser('start = .', options);
doesNotParseWithDetails(
anyParser,
"",
["any character"],
null,
'Expected any character but end of input found.'
);
var namedRuleWithLiteralParser = PEG.buildParser(
'start "digit" = [0-9]',
options
);
doesNotParseWithDetails(
namedRuleWithLiteralParser,
"a",
["digit"],
"a",
'Expected digit but "a" found.'
);
var namedRuleWithAnyParser = PEG.buildParser('start "whatever" = .', options);
doesNotParseWithDetails(
namedRuleWithAnyParser,
"",
["whatever"],
null,
'Expected whatever but end of input found.'
);
var namedRuleWithNamedRuleParser = PEG.buildParser([
'start "digits" = digit+',
'digit "digit" = [0-9]'
].join("\n"), options);
doesNotParseWithDetails(
namedRuleWithNamedRuleParser,
"",
["digits"],
null,
'Expected digits but end of input found.'
);
var choiceParser1 = PEG.buildParser('start = "a" / "b" / "c"', options);
doesNotParseWithDetails(
choiceParser1,
"def",
["\"a\"", "\"b\"", "\"c\""],
"d",
'Expected "a", "b" or "c" but "d" found.'
);
var choiceParser2 = PEG.buildParser('start = "a" "b" "c" / "a"', options);
doesNotParseWithDetails(
choiceParser2,
"abd",
["\"c\""],
"d",
'Expected "c" but "d" found.'
);
var simpleNotParser = PEG.buildParser('start = !"a" "b"', options);
doesNotParseWithDetails(
simpleNotParser,
"c",
["\"b\""],
"c",
'Expected "b" but "c" found.'
);
var simpleAndParser = PEG.buildParser('start = &"a" [a-b]', options);
doesNotParseWithDetails(
simpleAndParser,
"c",
[],
"c",
'Expected end of input but "c" found.'
);
var emptyParser = PEG.buildParser('start = ', options);
doesNotParseWithDetails(
emptyParser,
"something",
[],
"s",
'Expected end of input but "s" found.'
);
var duplicateErrorParser = PEG.buildParser('start = "a" / "a"', options);
doesNotParseWithDetails(
duplicateErrorParser,
"",
["\"a\""],
null,
'Expected "a" but end of input found.'
);
var unsortedErrorsParser = PEG.buildParser('start = "b" / "a"', options);
doesNotParseWithDetails(
unsortedErrorsParser,
"",
["\"a\"", "\"b\""],
null,
'Expected "a" or "b" but end of input found.'
);
});
testWithVaryingTrackLineAndColumn("error positions", function(options) {
var simpleParser = PEG.buildParser('start = "a"', options);
/* Regular match failure */
doesNotParseWithPos(simpleParser, "b", 0, 1, 1);
/* Trailing input */
doesNotParseWithPos(simpleParser, "ab", 1, 1, 2);
var digitsParser = PEG.buildParser([
'start = line (("\\r" / "\\n" / "\\u2028" / "\\u2029")+ line)*',
'line = digits (" "+ digits)*',
'digits = digits:[0-9]+ { return digits.join(""); }'
].join("\n"), options);
doesNotParseWithPos(digitsParser, "1\n2\n\n3\n\n\n4 5 x", 13, 7, 5);
/* Non-Unix newlines */
doesNotParseWithPos(digitsParser, "1\rx", 2, 2, 1); // Old Mac
doesNotParseWithPos(digitsParser, "1\r\nx", 3, 2, 1); // Windows
doesNotParseWithPos(digitsParser, "1\n\rx", 3, 3, 1); // mismatched
/* Strange newlines */
doesNotParseWithPos(digitsParser, "1\u2028x", 2, 2, 1); // line separator
doesNotParseWithPos(digitsParser, "1\u2029x", 2, 2, 1); // paragraph separator
});
testWithVaryingTrackLineAndColumn("start rule", function(options) {
var parser = PEG.buildParser([
'a = .* { return "alpha"; }',
'b = .* { return "beta"; }'
].join("\n"), options);
/* Default start rule = the first one */
parses(parser, "whatever", "alpha");
/* Explicit specification of the start rule */
parsesWithStartRule(parser, "whatever", "a", "alpha");
parsesWithStartRule(parser, "whatever", "b", "beta");
/* Invalid rule name */
raises(
function() { parser.parse("whatever", "c"); },
function(e) {
return e instanceof Error && e.message === "Invalid rule name: \"c\".";
}
);
});
})();