Dear Cafe,

This is a followup question to my previous one. Also asked as a Megaparsec question issue at https://github.com/mrkkrp/megaparsec/issues/429

As I observed (have no idea where a canonical definition could live for this) that for the contract of parser combinators:

Am I right about these rules? Where is the official specification of such rules?

Then I guess that empty result of a parser could mean NoMatch even after consumed some input, and want to leverage this semantic, but encountered error with current implementation https://github.com/complyue/dcp/blob/5be688396b7e2bda00ea80fd99d2a7b3ec5c788d/src/Parser.hs#L138-L146

artifactDecl :: Parser ArtDecl
artifactDecl = do
  artCmt <- immediateDocComments
  (eof >> empty) <|> do
    artBody <- takeWhileP (Just "artifact body")
                          (not . flip elem (";{" :: [Char]))
    if T.null $ T.strip artBody
      then empty -- this is not possible in real cases
      else return (artCmt, artBody)
$ cabal run dcp < samples/full.txt
Up to date
dcp: 73:1:
   |
73 | <empty line>
   | ^
expecting "{#", "{##", or artifact body

CallStack (from HasCallStack):
  error, called at src/Parser.hs:151:14 in main:Parser

So how can I achieve that?

Background is I'm trying to prototype an implementation of doc comment parsing as described at #428

Best regards,
Compl