Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using Trifecta's layout parser

I'm experimenting with Trifecta for parsing a very simple functional language with Haskell-like layout syntax. I'm working off the Haddock docs and my experience with Parsec, because I couldn't find any introductory material on Trifecta itself.

The problem I'm having is with using the layout stuff, since not even the Haddock docs help much.

Given the following code:

import Text.Trifecta
import Text.Trifecta.Parser.Token.Style
import Text.Trifecta.Parser.Identifier.Style
import Text.Trifecta.Layout.Combinators
import Text.Trifecta.Language.Prim

import Control.Applicative
import Control.Monad.Trans
import Data.Maybe (fromMaybe)

import Data.HashSet as HashSet
import Data.ByteString.UTF8 as UTF8

-- Copypasta from Text.Trifecta.Parser.Identifier.Style
set :: [String] -> HashSet ByteString
set = HashSet.fromList . fmap UTF8.fromString

lang :: MonadParser m => LanguageDef m
lang = LanguageDef{ languageCommentStyle = haskellCommentStyle
                  , languageIdentifierStyle = emptyIdents{ styleReserved = set keywords }
                  , languageOperatorStyle = emptyOps{ styleReserved = set ops }
                  }
  where
    keywords = ["where"]
    ops = ["="]

data Def = Def ByteString [ByteString] [ByteString] [Def]
         deriving Show

instance MonadLanguage m => MonadLanguage (Layout m) where
    askLanguage = fmap liftLanguageDef $ lift askLanguage

def :: (MonadParser m) => Layout (Language m) Def
def = Def <$> identifier <*> vars <* reservedOp "=" <*> vars <*> laidout locals
  where
    vars = many identifier
    locals = fromMaybe [] <$> optional (reserved "where" *> defs)

defs :: (MonadParser m) => Layout (Language m) [Def]
defs = laidout (many def)

test :: String -> IO ()
test =  parseTest $ run $ defs <* eof
  where
    run p = runLanguage (fst <$> runLayout p defaultLayoutState) lang

I'm trying to parse the following text with test:

f x = x y a b c -- 1
  where         -- 2
    y = d       -- 3
g x = z         -- 4

but it fails with this parse error:

(interactive):4:2: error: expected: "=",
    identifier, letter or digit
g x = z         -- 4 
 ^      

but if I comment out lines 2 and 3, it works.

So how do I make it parse even when including lines 2 and 3?

like image 673
Cactus Avatar asked Sep 11 '12 14:09

Cactus


1 Answers

There are a couple of bugs in the Layout support for Trifecta. I need to port some fixes back from the Scala implementation.

Notably a few things need to disable the start of line check that do not, so it tried to do automatic-semicolon insertion where you are getting the error.

I ported it from another codebase of mine that made slightly different assumptions and offered slightly different invariants than trifecta does.

This is actually a large part of why it isn't currently in the master branch on github.

Fixing it up to use the new parsers-based API, and porting those changes is the last major thing I need to do before I can ship 0.90.

In the meantime I wouldn't rely on it. My apologies.

I'll update this response as soon as it is stable.

like image 81
Edward Kmett Avatar answered Sep 27 '22 17:09

Edward Kmett