how to use megaparsec's combinators on StateT

239 views Asked by At

I'm building a compiler for java for university project, in my project my parsers are mostly StateT (Scope,SymbolTable) String m a where Scope is the scope we're at now(method,class,etc) and SymbolTable holds the symbols defined till now.

I wanted to use megaparsec's combinators on those parsers, for parens,braces it's not problem, I just use mapStateT but for sepBy and others I developed this function :

mapsequence :: (Monoid s,Monad m) => (m (a,(b,s)) -> m [(a,(b,s))]) -> StateT (b,s) m a -> StateT (b,s) m [a]
mapsequence f stm = do
                      s <- get
                      ases <- lift $ f $ runStateT stm s
                      case ases of
                        (_:_) -> do
                               put ((fst . snd . last) ases,(mconcat . map (snd . snd)) ases)
                               return $ map fst ases
                        [] -> return []

Now f would be for example :

\p -> p `sepBy` semi

Anyway I realized lately that the function above is wrong, the function will run the parser(encapsulated in StateT) feeding it the state we have right now which is s then it will run it again but instead of feeding it the new state resulting from the first run it will feed it s again and again and ... .

How do I use megaparsec's combinators like sepBy,sepEndBy and etc so that I run the parser many times but chaining the resulting state from the first to the second to the third etc ?

2

There are 2 answers

0
niceman On BEST ANSWER

I don't know why I thought that I needed a special function to do this, sepBy and others are defined on Alternative and because every StateT has an Alternative instance functions like sepBy,many, etc can be called directly.

My problem probably was because I had to use symbol,char,etc which I thought are ParsecT ... but then I realized those functions are defined in terms of MonadParsec typeclass which StateT again has instance for so I didn't even need lift or mapStateT.

So all I did is to change functions signatures to work with MonadParsec and my problem was solved.

1
Cactus On

Megaparsec has a monad transformer interface ParsecT:

data ParsecT e s m a

ParsecT e s m a is a parser with custom data component of error e, stream type s, underlying monad m and return type a.

You should be able to use this with something like type Parser = ParsecT Dec Text (State (Scope, SymbolTable)), which will add parsing functionality to the underlying State (Scope, SymbolTable) monad.