Using Trifecta's layout parser
Asked Answered
B

1

6

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?

Backwoodsman answered 11/9, 2012 at 14:34 Comment(0)
M
6

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.

Muller answered 11/9, 2012 at 21:56 Comment(3)
I imagine this is fixed now? trifecta is currently at 1.5.1.Fransis
We currently have the layout parser removed from the mainstream trifecta. However, you have good timing. I'm currently dusting it off and looking to replace it. =)Muller
@EdwardKMETT: Trifecta is now at version 2, is the layout parser planned to make a comeback?Backwoodsman

© 2022 - 2024 — McMap. All rights reserved.