stchang / parsack

A basic Parsec-like monadic parser combinator library implementation in Racket.
MIT License
50 stars 10 forks source link

Debugging? #25

Closed greghendershott closed 10 years ago

greghendershott commented 10 years ago

I found an input that causes my grammar never to terminate. It's difficult to understand where.

Is there some way I could see the parse execution, with the names of the combinators being called?

Using racket/trace doesn't seem to work for this. (Even if it did work, it would be time-consuming to supply all the functions it should trace, in a moderately big grammar.)

Can you get racket/trace to work for you, or is there some other way Parsack could help with this? Perhaps a debugging version of >>= that can log-debug the state and the combinator names as they're called??

stchang commented 10 years ago

I will look into a debug mode, although I'm not sure modifying >>= is the right place.

I would guess that your loop almost certainly involves some combination of many and lookAhead though. That is a danger of a parser that returns success without consuming input.

Something like: (parse (many (lookAhead (string "a"))) "a")

greghendershott commented 10 years ago

Example of the problem I need to fix: https://github.com/greghendershott/markdown/issues/26

In another case, which did terminate but with a syntax error, I was able to narrow down the randomly generated input to something shorter, then figure it out in my head.

In this example, I might eventually figure it out that way. But it would be a huge help to know that it's getting stuck on a many in $emph, for example.

greghendershott commented 10 years ago

Thanks for that advice. There are a few such candidates, and I'm starting with "nonsense" randomized input so it's not always easy to deduce from the input. So, not urgent, but, if you do think of any way to do trace style debugging, that would be great. Thanks again.

greghendershott commented 10 years ago

One quick thing I came up with was this helper I defined locally:

(define (parse-debug p s)
  (define-values (parsed more)
    (match (parse p s)
      [(Consumed! (Ok parsed (State more _) _)) (values parsed more)]
      [(Empty     (Ok parsed (State more _) _)) (values parsed more)]
      [x (parsack-error (~v x))]))
  (displayln "parsed:")
  (displayln parsed)
  (unless (equal? more "")
    (parse-debug p more)))

If the grammar has some top-level thing like (many $block), I can at least do (parse-debug $block input) and get a first approximation where it got stuck. That hasn't helped me in this case yet, but might in others.

Maybe a better named would be parse-many-debug.

stchang commented 10 years ago

Below is a hack I came up with. Basically overrides #%app. You'll have to sift through the output a bit or you can fiddle with conditionals to filter out some junk but the info should be in tere. Still trying to think of something better.

In a file debug.rkt:

#lang racket

(provide (except-out (all-from-out racket) #%app))
(provide (rename-out [app #%app]))
(define-syntax-rule (app f e ...)
  (begin
    (printf "fn: ~a\n" 'f)
    (printf "args: ~a\n" '(e ...))
    (#%app f e ...)))

Then in parsack.rkt replace #lang racket with #lang s-exp "debug.rkt"