Revert "Remove info about found string from syntax errors"

This reverts commit 25ab98027d.

Part of work on #428.
redux
David Majda 8 years ago
parent 4fe682794d
commit 6b60896216

@ -155,8 +155,8 @@ Using the Parser
Using the generated parser is simple — just call its `parse` method and pass an 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 input string as a parameter. The method will return a parse result (the exact
value depends on the grammar used to generate the parser) or throw an exception value depends on the grammar used to generate the parser) or throw an exception
if the input is invalid. The exception will contain `location`, `expected` and if the input is invalid. The exception will contain `location`, `expected`,
`message` properties with more details about the error. `found`, and `message` properties with more details about the error.
```javascript ```javascript
parser.parse("abba"); // returns ["a", "b", "b", "a"] parser.parse("abba"); // returns ["a", "b", "b", "a"]

@ -768,9 +768,10 @@ function generateJS(ast, options) {
' child.prototype = new ctor();', ' child.prototype = new ctor();',
'}', '}',
'', '',
'function peg$SyntaxError(message, expected, location) {', 'function peg$SyntaxError(message, expected, found, location) {',
' this.message = message;', ' this.message = message;',
' this.expected = expected;', ' this.expected = expected;',
' this.found = found;',
' this.location = location;', ' this.location = location;',
' this.name = "SyntaxError";', ' this.name = "SyntaxError";',
'', '',
@ -965,6 +966,7 @@ function generateJS(ast, options) {
' throw peg$buildException(', ' throw peg$buildException(',
' null,', ' null,',
' [{ type: "other", description: description }],', ' [{ type: "other", description: description }],',
' input.substring(peg$savedPos, peg$currPos),',
' location', ' location',
' );', ' );',
' }', ' }',
@ -972,7 +974,12 @@ function generateJS(ast, options) {
' function error(message, location) {', ' function error(message, location) {',
' location = location !== void 0 ? location : peg$computeLocation(peg$savedPos, peg$currPos)', ' location = location !== void 0 ? location : peg$computeLocation(peg$savedPos, peg$currPos)',
'', '',
' throw peg$buildException(message, null, location);', ' throw peg$buildException(',
' message,',
' null,',
' input.substring(peg$savedPos, peg$currPos),',
' location',
' );',
' }', ' }',
'', '',
' function peg$computePosDetails(pos) {', ' function peg$computePosDetails(pos) {',
@ -1037,7 +1044,7 @@ function generateJS(ast, options) {
' peg$maxFailExpected.push(expected);', ' peg$maxFailExpected.push(expected);',
' }', ' }',
'', '',
' function peg$buildException(message, expected, location) {', ' function peg$buildException(message, expected, found, location) {',
' function cleanupExpected(expected) {', ' function cleanupExpected(expected) {',
' var i, j;', ' var i, j;',
'', '',
@ -1067,9 +1074,36 @@ function generateJS(ast, options) {
' }', ' }',
' }', ' }',
'', '',
' function buildMessage(expected) {', ' function buildMessage(expected, found) {',
' function stringEscape(s) {',
' function hex(ch) { return ch.charCodeAt(0).toString(16).toUpperCase(); }',
'',
/*
* ECMA-262, 5th ed., 7.8.4: All characters may appear literally in a
* string literal except for the closing quote character, backslash,
* carriage return, line separator, paragraph separator, and line feed.
* Any character may appear in the form of an escape sequence.
*
* For portability, we also escape all control and non-ASCII characters.
* Note that "\0" and "\v" escape sequences are not used because JSHint
* does not like the first and IE the second.
*/
' return s',
' .replace(/\\\\/g, \'\\\\\\\\\')', // backslash
' .replace(/"/g, \'\\\\"\')', // closing double quote
' .replace(/\\x08/g, \'\\\\b\')', // backspace
' .replace(/\\t/g, \'\\\\t\')', // horizontal tab
' .replace(/\\n/g, \'\\\\n\')', // line feed
' .replace(/\\f/g, \'\\\\f\')', // form feed
' .replace(/\\r/g, \'\\\\r\')', // carriage return
' .replace(/[\\x00-\\x07\\x0B\\x0E\\x0F]/g, function(ch) { return \'\\\\x0\' + hex(ch); })',
' .replace(/[\\x10-\\x1F\\x80-\\xFF]/g, function(ch) { return \'\\\\x\' + hex(ch); })',
' .replace(/[\\u0100-\\u0FFF]/g, function(ch) { return \'\\\\u0\' + hex(ch); })',
' .replace(/[\\u1000-\\uFFFF]/g, function(ch) { return \'\\\\u\' + hex(ch); });',
' }',
'',
' var expectedDescs = new Array(expected.length),', ' var expectedDescs = new Array(expected.length),',
' expectedDesc, i;', ' expectedDesc, foundDesc, i;',
'', '',
' for (i = 0; i < expected.length; i++) {', ' for (i = 0; i < expected.length; i++) {',
' expectedDescs[i] = expected[i].description;', ' expectedDescs[i] = expected[i].description;',
@ -1081,7 +1115,9 @@ function generateJS(ast, options) {
' + expectedDescs[expected.length - 1]', ' + expectedDescs[expected.length - 1]',
' : expectedDescs[0];', ' : expectedDescs[0];',
'', '',
' return "Expected " + expectedDesc + ".";', ' foundDesc = found ? "\\"" + stringEscape(found) + "\\"" : "end of input";',
'',
' return "Expected " + expectedDesc + " but " + foundDesc + " found.";',
' }', ' }',
'', '',
' if (expected !== null) {', ' if (expected !== null) {',
@ -1089,8 +1125,9 @@ function generateJS(ast, options) {
' }', ' }',
'', '',
' return new peg$SyntaxError(', ' return new peg$SyntaxError(',
' message !== null ? message : buildMessage(expected),', ' message !== null ? message : buildMessage(expected, found),',
' expected,', ' expected,',
' found,',
' location', ' location',
' );', ' );',
' }', ' }',
@ -1130,7 +1167,10 @@ function generateJS(ast, options) {
' throw peg$buildException(', ' throw peg$buildException(',
' null,', ' null,',
' peg$maxFailExpected,', ' peg$maxFailExpected,',
' peg$computeLocation(peg$maxFailPos, peg$maxFailPos)', ' peg$maxFailPos < input.length ? input.charAt(peg$maxFailPos) : null,',
' peg$maxFailPos < input.length',
' ? peg$computeLocation(peg$maxFailPos, peg$maxFailPos + 1)',
' : peg$computeLocation(peg$maxFailPos, peg$maxFailPos)',
' );', ' );',
' }', ' }',
'}' '}'

@ -21,9 +21,10 @@
child.prototype = new ctor(); child.prototype = new ctor();
} }
function peg$SyntaxError(message, expected, location) { function peg$SyntaxError(message, expected, found, location) {
this.message = message; this.message = message;
this.expected = expected; this.expected = expected;
this.found = found;
this.location = location; this.location = location;
this.name = "SyntaxError"; this.name = "SyntaxError";
@ -427,6 +428,7 @@
throw peg$buildException( throw peg$buildException(
null, null,
[{ type: "other", description: description }], [{ type: "other", description: description }],
input.substring(peg$savedPos, peg$currPos),
location location
); );
} }
@ -434,7 +436,12 @@
function error(message, location) { function error(message, location) {
location = location !== void 0 ? location : peg$computeLocation(peg$savedPos, peg$currPos) location = location !== void 0 ? location : peg$computeLocation(peg$savedPos, peg$currPos)
throw peg$buildException(message, null, location); throw peg$buildException(
message,
null,
input.substring(peg$savedPos, peg$currPos),
location
);
} }
function peg$computePosDetails(pos) { function peg$computePosDetails(pos) {
@ -499,7 +506,7 @@
peg$maxFailExpected.push(expected); peg$maxFailExpected.push(expected);
} }
function peg$buildException(message, expected, location) { function peg$buildException(message, expected, found, location) {
function cleanupExpected(expected) { function cleanupExpected(expected) {
var i, j; var i, j;
@ -524,9 +531,26 @@
} }
} }
function buildMessage(expected) { function buildMessage(expected, found) {
function stringEscape(s) {
function hex(ch) { return ch.charCodeAt(0).toString(16).toUpperCase(); }
return s
.replace(/\\/g, '\\\\')
.replace(/"/g, '\\"')
.replace(/\x08/g, '\\b')
.replace(/\t/g, '\\t')
.replace(/\n/g, '\\n')
.replace(/\f/g, '\\f')
.replace(/\r/g, '\\r')
.replace(/[\x00-\x07\x0B\x0E\x0F]/g, function(ch) { return '\\x0' + hex(ch); })
.replace(/[\x10-\x1F\x80-\xFF]/g, function(ch) { return '\\x' + hex(ch); })
.replace(/[\u0100-\u0FFF]/g, function(ch) { return '\\u0' + hex(ch); })
.replace(/[\u1000-\uFFFF]/g, function(ch) { return '\\u' + hex(ch); });
}
var expectedDescs = new Array(expected.length), var expectedDescs = new Array(expected.length),
expectedDesc, i; expectedDesc, foundDesc, i;
for (i = 0; i < expected.length; i++) { for (i = 0; i < expected.length; i++) {
expectedDescs[i] = expected[i].description; expectedDescs[i] = expected[i].description;
@ -538,7 +562,9 @@
+ expectedDescs[expected.length - 1] + expectedDescs[expected.length - 1]
: expectedDescs[0]; : expectedDescs[0];
return "Expected " + expectedDesc + "."; foundDesc = found ? "\"" + stringEscape(found) + "\"" : "end of input";
return "Expected " + expectedDesc + " but " + foundDesc + " found.";
} }
if (expected !== null) { if (expected !== null) {
@ -546,8 +572,9 @@
} }
return new peg$SyntaxError( return new peg$SyntaxError(
message !== null ? message : buildMessage(expected), message !== null ? message : buildMessage(expected, found),
expected, expected,
found,
location location
); );
} }
@ -4948,7 +4975,10 @@
throw peg$buildException( throw peg$buildException(
null, null,
peg$maxFailExpected, peg$maxFailExpected,
peg$computeLocation(peg$maxFailPos, peg$maxFailPos) peg$maxFailPos < input.length ? input.charAt(peg$maxFailPos) : null,
peg$maxFailPos < input.length
? peg$computeLocation(peg$maxFailPos, peg$maxFailPos + 1)
: peg$computeLocation(peg$maxFailPos, peg$maxFailPos)
); );
} }
} }

@ -1219,8 +1219,9 @@ describe("generated parser behavior", function() {
); );
expect(parser).toFailToParse("a", { expect(parser).toFailToParse("a", {
message: 'Expected a.', message: 'Expected a but "a" found.',
expected: [{ type: "other", description: "a" }], expected: [{ type: "other", description: "a" }],
found: "a",
location: { location: {
start: { offset: 0, line: 1, column: 1 }, start: { offset: 0, line: 1, column: 1 },
end: { offset: 1, line: 1, column: 2 } end: { offset: 1, line: 1, column: 2 }
@ -1239,8 +1240,9 @@ describe("generated parser behavior", function() {
].join("\n"), options); ].join("\n"), options);
expect(parser).toFailToParse("a", { expect(parser).toFailToParse("a", {
message: 'Expected a.', message: 'Expected a but "a" found.',
expected: [{ type: "other", description: "a" }], expected: [{ type: "other", description: "a" }],
found: "a",
location: { location: {
start: { offset: 1, line: 1, column: 2 }, start: { offset: 1, line: 1, column: 2 },
end: { offset: 2, line: 1, column: 3 } end: { offset: 2, line: 1, column: 3 }
@ -1258,6 +1260,7 @@ describe("generated parser behavior", function() {
expect(parser).toFailToParse("a", { expect(parser).toFailToParse("a", {
message: "a", message: "a",
found: "a",
expected: null, expected: null,
location: { location: {
start: { offset: 0, line: 1, column: 1 }, start: { offset: 0, line: 1, column: 1 },
@ -1279,6 +1282,7 @@ describe("generated parser behavior", function() {
expect(parser).toFailToParse("a", { expect(parser).toFailToParse("a", {
message: "a", message: "a",
expected: null, expected: null,
found: "a",
location: { location: {
start: { offset: 1, line: 1, column: 2 }, start: { offset: 1, line: 1, column: 2 },
end: { offset: 2, line: 1, column: 3 } end: { offset: 2, line: 1, column: 3 }
@ -1395,12 +1399,26 @@ describe("generated parser behavior", function() {
}); });
}); });
describe("found string reporting", function() {
it("reports found string correctly at the end of input", function() {
var parser = peg.generate('start = "a"', options);
expect(parser).toFailToParse("", { found: null });
});
it("reports found string correctly in the middle of input", function() {
var parser = peg.generate('start = "a"', options);
expect(parser).toFailToParse("b", { found: "b" });
});
});
describe("message building", function() { describe("message building", function() {
it("builds message correctly with no alternative", function() { it("builds message correctly with no alternative", function() {
var parser = peg.generate('start = "a"', options); var parser = peg.generate('start = "a"', options);
expect(parser).toFailToParse("ab", { expect(parser).toFailToParse("ab", {
message: 'Expected end of input.' message: 'Expected end of input but "b" found.'
}); });
}); });
@ -1408,7 +1426,7 @@ describe("generated parser behavior", function() {
var parser = peg.generate('start = "a"', options); var parser = peg.generate('start = "a"', options);
expect(parser).toFailToParse("b", { expect(parser).toFailToParse("b", {
message: 'Expected "a".' message: 'Expected "a" but "b" found.'
}); });
}); });
@ -1416,16 +1434,32 @@ describe("generated parser behavior", function() {
var parser = peg.generate('start = "a" / "b" / "c"', options); var parser = peg.generate('start = "a" / "b" / "c"', options);
expect(parser).toFailToParse("d", { expect(parser).toFailToParse("d", {
message: 'Expected "a", "b" or "c".' message: 'Expected "a", "b" or "c" but "d" found.'
});
});
it("builds message correctly at the end of input", function() {
var parser = peg.generate('start = "a"', options);
expect(parser).toFailToParse("", {
message: 'Expected "a" but end of input found.'
});
});
it("builds message correctly in the middle of input", function() {
var parser = peg.generate('start = "a"', options);
expect(parser).toFailToParse("b", {
message: 'Expected "a" but "b" found.'
}); });
}); });
}); });
describe("position reporting", function() { describe("position reporting", function() {
it("reports position correctly with no trailing input", function() { it("reports position correctly at the end of input", function() {
var parser = peg.generate('start = "a"', options); var parser = peg.generate('start = "a"', options);
expect(parser).toFailToParse("b", { expect(parser).toFailToParse("", {
location: { location: {
start: { offset: 0, line: 1, column: 1 }, start: { offset: 0, line: 1, column: 1 },
end: { offset: 0, line: 1, column: 1 } end: { offset: 0, line: 1, column: 1 }
@ -1433,13 +1467,24 @@ describe("generated parser behavior", function() {
}); });
}); });
it("reports position correctly in the middle of input", function() {
var parser = peg.generate('start = "a"', options);
expect(parser).toFailToParse("b", {
location: {
start: { offset: 0, line: 1, column: 1 },
end: { offset: 1, line: 1, column: 2 }
}
});
});
it("reports position correctly with trailing input", function() { it("reports position correctly with trailing input", function() {
var parser = peg.generate('start = "a"', options); var parser = peg.generate('start = "a"', options);
expect(parser).toFailToParse("aa", { expect(parser).toFailToParse("aa", {
location: { location: {
start: { offset: 1, line: 1, column: 2 }, start: { offset: 1, line: 1, column: 2 },
end: { offset: 1, line: 1, column: 2 } end: { offset: 2, line: 1, column: 3 }
} }
}); });
}); });
@ -1455,7 +1500,7 @@ describe("generated parser behavior", function() {
expect(parser).toFailToParse("1\n2\n\n3\n\n\n4 5 x", { expect(parser).toFailToParse("1\n2\n\n3\n\n\n4 5 x", {
location: { location: {
start: { offset: 13, line: 7, column: 5 }, start: { offset: 13, line: 7, column: 5 },
end: { offset: 13, line: 7, column: 5 } end: { offset: 14, line: 7, column: 6 }
} }
}); });
@ -1463,13 +1508,13 @@ describe("generated parser behavior", function() {
expect(parser).toFailToParse("1\nx", { // Old Mac expect(parser).toFailToParse("1\nx", { // Old Mac
location: { location: {
start: { offset: 2, line: 2, column: 1 }, start: { offset: 2, line: 2, column: 1 },
end: { offset: 2, line: 2, column: 1 } end: { offset: 3, line: 2, column: 2 }
} }
}); });
expect(parser).toFailToParse("1\r\nx", { // Windows expect(parser).toFailToParse("1\r\nx", { // Windows
location: { location: {
start: { offset: 3, line: 2, column: 1 }, start: { offset: 3, line: 2, column: 1 },
end: { offset: 3, line: 2, column: 1 } end: { offset: 4, line: 2, column: 2 }
} }
}); });
}); });

Loading…
Cancel
Save