Browse Source

Support passing custom location info to "error" and "expected"

Based on a pull request by Konstantin (@YemSalat):

  https://github.com/pegjs/pegjs/pull/391

Resolves #390.
redux
David Majda 6 years ago
parent
commit
ce44c62f14
  1. 13
      README.md
  2. 16
      lib/compiler/passes/generate-js.js
  3. 16
      lib/parser.js
  4. 92
      spec/behavior/generated-parser-behavior.spec.js

13
README.md

@ -403,13 +403,16 @@ using the `return` statement. This value is considered match result of the
preceding expression.
To indicate an error, the code inside the action can invoke the `expected`
function, which makes the parser throw an exception. The function takes one
parameter — a description of what was expected at the current position. This
description will be used as part of a message of the thrown exception.
function, which makes the parser throw an exception. The function takes two
parameters — a description of what was expected at the current position and
optional location information (the default is what `location` would return — see
below). The description will be used as part of a message of the thrown
exception.
The code inside an action can also invoke the `error` function, which also makes
the parser throw an exception. The function takes one parameter — an error
message. This message will be used by the thrown exception.
the parser throw an exception. The function takes two parameters — an error
message and optional location information (the default is what `location` would
return — see below). The message will be used by the thrown exception.
The code inside the action can access all variables and functions defined in the
initializer at the beginning of the grammar. Curly braces in the action code

16
lib/compiler/passes/generate-js.js

@ -967,20 +967,20 @@ function generateJS(ast, options) {
' return peg$computeLocation(peg$savedPos, peg$currPos);',
' }',
'',
' function expected(description) {',
' function expected(description, location) {',
' location = location !== void 0 ? location : peg$computeLocation(peg$savedPos, peg$currPos)',
'',
' throw peg$buildException(',
' null,',
' [{ type: "other", description: description }],',
' peg$computeLocation(peg$savedPos, peg$currPos)',
' location',
' );',
' }',
'',
' function error(message) {',
' throw peg$buildException(',
' message,',
' null,',
' peg$computeLocation(peg$savedPos, peg$currPos)',
' );',
' function error(message, location) {',
' location = location !== void 0 ? location : peg$computeLocation(peg$savedPos, peg$currPos)',
'',
' throw peg$buildException(message, null, location);',
' }',
'',
' function peg$computePosDetails(pos) {',

16
lib/parser.js

@ -416,20 +416,20 @@ module.exports = (function() {
return peg$computeLocation(peg$savedPos, peg$currPos);
}
function expected(description) {
function expected(description, location) {
location = location !== void 0 ? location : peg$computeLocation(peg$savedPos, peg$currPos)
throw peg$buildException(
null,
[{ type: "other", description: description }],
peg$computeLocation(peg$savedPos, peg$currPos)
location
);
}
function error(message) {
throw peg$buildException(
message,
null,
peg$computeLocation(peg$savedPos, peg$currPos)
);
function error(message, location) {
location = location !== void 0 ? location : peg$computeLocation(peg$savedPos, peg$currPos)
throw peg$buildException(message, null, location);
}
function peg$computePosDetails(pos) {

92
spec/behavior/generated-parser-behavior.spec.js

@ -1211,35 +1211,79 @@ describe("generated parser behavior", function() {
});
});
it("|expected| terminates parsing and throws an exception", function() {
var parser = PEG.buildParser(
'start = "a" { expected("a"); }',
options
);
describe("|expected|", function() {
it("terminates parsing and throws an exception", function() {
var parser = PEG.buildParser(
'start = "a" { expected("a"); }',
options
);
expect(parser).toFailToParse("a", {
message: 'Expected a.',
expected: [{ type: "other", description: "a" }],
location: {
start: { offset: 0, line: 1, column: 1 },
end: { offset: 1, line: 1, column: 2 }
}
expect(parser).toFailToParse("a", {
message: 'Expected a.',
expected: [{ type: "other", description: "a" }],
location: {
start: { offset: 0, line: 1, column: 1 },
end: { offset: 1, line: 1, column: 2 }
}
});
});
it("allows to set custom location info", function() {
var parser = PEG.buildParser([
'start = "a" {',
' expected("a", {',
' start: { offset: 1, line: 1, column: 2 },',
' end: { offset: 2, line: 1, column: 3 }',
' });',
'}'
].join("\n"), options);
expect(parser).toFailToParse("a", {
message: 'Expected a.',
expected: [{ type: "other", description: "a" }],
location: {
start: { offset: 1, line: 1, column: 2 },
end: { offset: 2, line: 1, column: 3 }
}
});
});
});
it("|error| terminates parsing and throws an exception", function() {
var parser = PEG.buildParser(
'start = "a" { error("a"); }',
options
);
describe("|error|", function() {
it("terminates parsing and throws an exception", function() {
var parser = PEG.buildParser(
'start = "a" { error("a"); }',
options
);
expect(parser).toFailToParse("a", {
message: "a",
expected: null,
location: {
start: { offset: 0, line: 1, column: 1 },
end: { offset: 1, line: 1, column: 2 }
}
expect(parser).toFailToParse("a", {
message: "a",
expected: null,
location: {
start: { offset: 0, line: 1, column: 1 },
end: { offset: 1, line: 1, column: 2 }
}
});
});
it("allows to set custom location info", function() {
var parser = PEG.buildParser([
'start = "a" {',
' error("a", {',
' start: { offset: 1, line: 1, column: 2 },',
' end: { offset: 2, line: 1, column: 3 }',
' });',
'}'
].join("\n"), options);
expect(parser).toFailToParse("a", {
message: "a",
expected: null,
location: {
start: { offset: 1, line: 1, column: 2 },
end: { offset: 2, line: 1, column: 3 }
}
});
});
});
});

Loading…
Cancel
Save