-
Notifications
You must be signed in to change notification settings - Fork 126
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Incorrectly set furthest value in lookahead? #296
Comments
(I'm not the maintainer, just some person who digs combinatory parsing libraries.)
Trying a minimal example: const P = require('parsimmon')
const both = (parser1, parser2) => P.lookahead(parser1).then(parser2)
const a = P.regex(/[aA]/).desc('a or A')
const caps = P.regex(/[A-Z]/).desc('capital letter A-Z')
const aCaps = both(a, caps)
console.log(aCaps.parse('A')) // both should succeed
console.log(aCaps.parse('b')) // a should fail
console.log(aCaps.parse('a')) // caps should fail Output:
In each failure, the
Does my example match what you're trying to do in principle? If so, I think there must be something else going on. |
Hey @anko, thanks for thinking on this. The following is closer to what I'm actually working with, and does seem to reproduce what I'm seeing: const both = (parser1, parser2) => P.lookahead(parser1).then(parser2)
const par = both(
P.regex(/[a-z0-9]/).times(2).skip(P.string(',')).many().skip(P.eof),
P.seq(
P.letters.skip(P.string(',')),
P.digits.skip(P.string(',')),
P.letters.skip(P.string(',')),
P.eof
)
);
console.log(par.parse('ab,12,cde,')); // Should fail only the first parser in both()
console.log(par.parse('ab,12,c2,')); // Should fail only the second parser in both() That spits out {
status: false,
index: { offset: 8, line: 1, column: 9 },
expected: [ "','" ]
}
{
status: false,
index: { offset: 9, line: 1, column: 10 },
expected: [ '/[a-z0-9]/' ]
} If I just run that second parser (starting with {
status: false,
index: { offset: 7, line: 1, column: 8 },
expected: [ "','" ]
} which is what I would expect. The |
Thanks for the comment @anko, always nice to see you in these Parsimmon threads :) @tstodter Thanks for the kind words! I would definitely suggest using I think I see what you're mentioning about the I made an example here https://runkit.com/wavebeem/parsimmon-issues-296/5.0.0 and I was surprised by the 2nd output... I think you may be correct and this might be a bug. |
Hmm, |
OK so I made the smallest possible (I think) repro of this bug: https://runkit.com/wavebeem/parsimmon-issues-296/6.0.0 I'm not sure if there's any way to fix this bug without breaking... well probably everybody's parsers. The issue seems to be inside of |
It does seem like a fix wouldn't change the final success/failure status, though it would change any error messages, so perhaps that's a small favor. That Do you think it's correct to write a version of |
sure, i mean you could totally copy the function and modify it for use in your own code: function lookahead(x) {
if (isParser(x)) {
return Parsimmon(function(input, i) {
var result = x._(input, i);
result.index = i;
result.value = "";
result.furthest = -1; // hack
return result;
});
} else if (typeof x === "string") {
return lookahead(string(x));
} else if (x instanceof RegExp) {
return lookahead(regexp(x));
}
throw new Error("not a string, regexp, or parser: " + x);
} You could also use https://runkit.com/wavebeem/parsimmon-issues-296-alternative/2.0.0 |
and yeah, "fixing" this should only change the error messages, but i found lots of tests that returned empty (!!) "expected" arrays for parse failures, which is clearly not a good thing |
First, thank you for your work on this library. It's been a real pleasure to work with the last few days and really just astonishingly easy. However, I've hit a small hiccup I was hoping to get some help with.
I'm trying to define a combinator to parse the same input with two different parsers, failing if either fails, succeeding only if both succeed, and keeping only the second result. A
&&
for parsers, basically (apologies if this already exists in the API and I just missed it).I had hoped to implement this as
const both = (parser1, parser2) => P.lookahead(parser1).chain(() => parser2)
or justP.lookahead(parser1).then(parser2)
, so I could use it something likeThis works just fine if both succeed or the first fails, but they eat the details of any failure produced by
parser2
. Ifparser1
succeeds andparser2
fails, parser produced byboth
will fail, but the final result will have theexpected
array of the first parser and it loses the much-more-informative error of the second parser.On investigation, I found that
mergeReplies
was preferringparser1
's result data because the parser produced bylookahead(x)
keeps whateverfurthest
value was generated byx
. Still trying to grok the library internals, but either of the following get me the behavior I'm looking forSo a couple questions. Am I understanding the internals or API here correctly? If so, should lookahead be setting
furthest
manually to -1, or be returning a makeSuccess()?The text was updated successfully, but these errors were encountered: