question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Incorrectly set furthest value in lookahead?

See original GitHub issue

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 just P.lookahead(parser1).then(parser2), so I could use it something like

const FileParser = both(
  P.regex(/[^\n]/).times(94).skip(P.end).many()
    .desc('all lines of 94 characters'),
  <long involved parser that seems to work fine alone>
);

This works just fine if both succeed or the first fails, but they eat the details of any failure produced by parser2. If parser1 succeeds and parser2 fails, parser produced by both will fail, but the final result will have the expected array of the first parser and it loses the much-more-informative error of the second parser.

On investigation, I found that mergeReplies was preferring parser1’s result data because the parser produced by lookahead(x) keeps whatever furthest value was generated by x. Still trying to grok the library internals, but either of the following get me the behavior I’m looking for

const both = (parser1, parser2) => (
  P.Parser((input, i) => {
    const result1 = parser1.parse(input);
    return !result1.status
      ? P.makeFailure(result1.index.offset, result1.expected)
      : P.makeSuccess(i, '');
  })
  .then(parser2)
);
// in parsimmon.js
function lookahead(x) {
  if (isParser(x)) {
    return Parsimmon(function(input, i) {
      var result = x._(input, i);
      result.index = i;
      result.value = "";
      result.furthest = -1; // Adding this here
      return result;
    });
  } else if (typeof x === "string") {
......

So 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()?

Issue Analytics

  • State:closed
  • Created 3 years ago
  • Comments:8 (1 by maintainers)

github_iconTop GitHub Comments

1reaction
wavebeemcommented, May 19, 2020

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 lookahead combined with then as @anko suggested. Also, you have a missing detail in your “all lines are 94 characters” parser. You need to add .then(P.eof) to test that you hit the end of the file. .many() matches ZERO or more times, so if this parser fails to parse, it will just parse zero times and succeed.

I think I see what you’re mentioning about the result.furthest = -1 thing… I’ll do some investigation on this and see what I find out.

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.

0reactions
wavebeemcommented, May 20, 2020

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

Read more comments on GitHub >

github_iconTop Results From Across the Web

Lookahead and Lookbehind Tutorial—Tips &Tricks - RexEgg
Explains the fine details of Lookahead and Lookbehind, including zero-width ... Now imagine we set \A in fourth position, after the three lookaheads....
Read more >
RPP: when far off path but within costmap, min approach velocity is ...
"If I request a lookahead distance, and the actual distance from the lookahead point is shorter enough, then I must be at the...
Read more >
Lookahead and Lookbehind Zero-Length Assertions
Because the lookahead is negative, this means that the lookahead has successfully matched at the current position. At this point, the entire regex...
Read more >
What's wrong with my lookahead regex in GNU sed?
This is fine for an anchored expression like ^foo , but unfortunately doesn't extend to the general case of negative lookahead anywhere in...
Read more >
CS264: Homework #2 - Tim Roughgarden
(7) Exercises are worth 5 points each. Problem parts are labeled with point values. (8) No late assignments will be accepted. Lecture 3...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found