Search code examples
haskellparsec

How can a custom Stream type influence the position info. in Parsec?


I'm using Parsec with a custom Stream type. This stream is essentially String but sometimes it expands input it finds in the string into other strings (think alias expansion). For example, given "§4.1 ¶3" it might feed "Section 4.1 paragraph 3" to the parser.

I have this all working. My types look like:

data DealiasingStream = ...
instance (Monad m) => Stream DealiasingStream m Char where ...

type ShellParser = Parsec DealiasingStream ()

Notice that the dependent type of DealiasingStream is just Char. This allows my parsers (well, my ShellParsers to use all the standard character parsers.

My question is about getting Parsec to report the positions in terms of the original input to my stream. The documentation for Stream says:

A Stream instance is responsible for maintaining the "position within the stream" in the stream state s. This is trivial unless you are using the monad in a non-trivial way.

Indeed, my stream type knows what position it wants to report at any given moment... but I don't see how to get Parsec to use it! Parsec seems to maintain its own SourcePos as part of its internal State. And this seems to be updated by the various token prims, and hence for the standard Char parsers, out of my control.

How is one supposed to do this?


Solution

  • I agree with your understanding — there's no easy way to control the position without rewriting functions such as char.

    What the documentation means is that the Stream instance is responsible for recording the position information inside the tokens. That information then can be used in functions like token or tokenPrim (by supplying appropriate position-calculating functions to them).

    Thus, you have to wrap Char into a datatype that includes position information and rewrite the basic functions using the primitives like token or tokenPrim that are flexible about the position calculation.