Browse Source

Add |offset| property to exceptions thrown by parsers

Based on a patch by Marcin Stefaniuk (marcin@stefaniuk.info).
redux
David Majda 10 years ago
parent
commit
21c6d9ccd3
  1. 2
      README.md
  2. 4
      src/emitter.js
  3. 4
      src/parser.js
  4. 16
      test/compiler-test.js
  5. 3
      test/helpers.js

2
README.md

@ -70,7 +70,7 @@ To get parser’s source code, call the `toSource` method on 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"]

4
src/emitter.js

@ -443,6 +443,7 @@ PEG.compiler.emitter = function(ast) {
' var errorPosition = computeErrorPosition();',
' throw new this.SyntaxError(',
' buildErrorMessage(),',
' Math.max(pos, rightmostFailuresPos),',
' errorPosition.line,',
' errorPosition.column',
' );',
@ -457,9 +458,10 @@ PEG.compiler.emitter = function(ast) {
' ',
' /* 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.message = message;',
' this.offset = offset;',
' this.line = line;',
' this.column = column;',
' };',

4
src/parser.js

@ -3598,6 +3598,7 @@ PEG.parser = (function(){
var errorPosition = computeErrorPosition();
throw new this.SyntaxError(
buildErrorMessage(),
Math.max(pos, rightmostFailuresPos),
errorPosition.line,
errorPosition.column
);
@ -3612,9 +3613,10 @@ PEG.parser = (function(){
/* 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.message = message;
this.offset = offset;
this.line = line;
this.column = column;
};

16
test/compiler-test.js

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

3
test/helpers.js

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

Loading…
Cancel
Save