Add |offset| property to exceptions thrown by parsers

Based on a patch by Marcin Stefaniuk (marcin@stefaniuk.info).
redux
David Majda 12 years ago
parent 8ae3eea7c4
commit 21c6d9ccd3

@ -70,7 +70,7 @@ To get parsers source code, call the `toSource` method on the parser.
Using the Parser Using the Parser
---------------- ----------------
Using the generated parser is simple — just call its `parse` method and pass an input string as a parameter. The method will return a parse result (the exact value depends on the grammar used to build the parser) or throw an exception if the input is invalid. The exception will contain `line`, `column` and `message` properties with more details about the error. Using the generated parser is simple — just call its `parse` method and pass an input string as a parameter. The method will return a parse result (the exact value depends on the grammar used to build the parser) or throw an exception if the input is invalid. The exception will contain `offset`, `line`, `column` and `message` properties with more details about the error.
parser.parse("abba"); // returns ["a", "b", "b", "a"] parser.parse("abba"); // returns ["a", "b", "b", "a"]

@ -443,6 +443,7 @@ PEG.compiler.emitter = function(ast) {
' var errorPosition = computeErrorPosition();', ' var errorPosition = computeErrorPosition();',
' throw new this.SyntaxError(', ' throw new this.SyntaxError(',
' buildErrorMessage(),', ' buildErrorMessage(),',
' Math.max(pos, rightmostFailuresPos),',
' errorPosition.line,', ' errorPosition.line,',
' errorPosition.column', ' errorPosition.column',
' );', ' );',
@ -457,9 +458,10 @@ PEG.compiler.emitter = function(ast) {
' ', ' ',
' /* Thrown when a parser encounters a syntax error. */', ' /* Thrown when a parser encounters a syntax error. */',
' ', ' ',
' result.SyntaxError = function(message, line, column) {', ' result.SyntaxError = function(message, offset, line, column) {',
' this.name = "SyntaxError";', ' this.name = "SyntaxError";',
' this.message = message;', ' this.message = message;',
' this.offset = offset;',
' this.line = line;', ' this.line = line;',
' this.column = column;', ' this.column = column;',
' };', ' };',

@ -3598,6 +3598,7 @@ PEG.parser = (function(){
var errorPosition = computeErrorPosition(); var errorPosition = computeErrorPosition();
throw new this.SyntaxError( throw new this.SyntaxError(
buildErrorMessage(), buildErrorMessage(),
Math.max(pos, rightmostFailuresPos),
errorPosition.line, errorPosition.line,
errorPosition.column errorPosition.column
); );
@ -3612,9 +3613,10 @@ PEG.parser = (function(){
/* Thrown when a parser encounters a syntax error. */ /* Thrown when a parser encounters a syntax error. */
result.SyntaxError = function(message, line, column) { result.SyntaxError = function(message, offset, line, column) {
this.name = "SyntaxError"; this.name = "SyntaxError";
this.message = message; this.message = message;
this.offset = offset;
this.line = line; this.line = line;
this.column = column; this.column = column;
}; };

@ -447,10 +447,10 @@ test("error positions", function() {
var simpleParser = PEG.buildParser('start = "a"'); var simpleParser = PEG.buildParser('start = "a"');
/* Regular match failure */ /* Regular match failure */
doesNotParseWithPos(simpleParser, "b", 1, 1); doesNotParseWithPos(simpleParser, "b", 0, 1, 1);
/* Trailing input */ /* Trailing input */
doesNotParseWithPos(simpleParser, "ab", 1, 2); doesNotParseWithPos(simpleParser, "ab", 1, 1, 2);
var digitsParser = PEG.buildParser([ var digitsParser = PEG.buildParser([
'start = line (("\\r" / "\\n" / "\\u2028" / "\\u2029")+ line)*', 'start = line (("\\r" / "\\n" / "\\u2028" / "\\u2029")+ line)*',
@ -458,16 +458,16 @@ test("error positions", function() {
'digits = digits:[0-9]+ { return digits.join(""); }' 'digits = digits:[0-9]+ { return digits.join(""); }'
].join("\n")); ].join("\n"));
doesNotParseWithPos(digitsParser, "1\n2\n\n3\n\n\n4 5 x", 7, 5); doesNotParseWithPos(digitsParser, "1\n2\n\n3\n\n\n4 5 x", 13, 7, 5);
/* Non-Unix newlines */ /* Non-Unix newlines */
doesNotParseWithPos(digitsParser, "1\rx", 2, 1); // Old Mac doesNotParseWithPos(digitsParser, "1\rx", 2, 2, 1); // Old Mac
doesNotParseWithPos(digitsParser, "1\r\nx", 2, 1); // Windows doesNotParseWithPos(digitsParser, "1\r\nx", 3, 2, 1); // Windows
doesNotParseWithPos(digitsParser, "1\n\rx", 3, 1); // mismatched doesNotParseWithPos(digitsParser, "1\n\rx", 3, 3, 1); // mismatched
/* Strange newlines */ /* Strange newlines */
doesNotParseWithPos(digitsParser, "1\u2028x", 2, 1); // line separator doesNotParseWithPos(digitsParser, "1\u2028x", 2, 2, 1); // line separator
doesNotParseWithPos(digitsParser, "1\u2029x", 2, 1); // paragraph separator doesNotParseWithPos(digitsParser, "1\u2029x", 2, 2, 1); // paragraph separator
}); });
test("start rule", function() { test("start rule", function() {

@ -19,11 +19,12 @@ doesNotParseWithMessage = function(parser, input, message) {
); );
}; };
doesNotParseWithPos = function(parser, input, line, column) { doesNotParseWithPos = function(parser, input, offset, line, column) {
raises( raises(
function() { parser.parse(input); }, function() { parser.parse(input); },
function(e) { function(e) {
return e instanceof parser.SyntaxError return e instanceof parser.SyntaxError
&& e.offset === offset
&& e.line === line && e.line === line
&& e.column === column; && e.column === column;
} }

Loading…
Cancel
Save