indentation-trifecta (empty) → 0.0
raw patch · 7 files changed
+405/−0 lines, 7 filesdep +basedep +indentation-coredep +indentation-trifectasetup-changed
Dependencies added: base, indentation-core, indentation-trifecta, mtl, parsers, tasty, tasty-hunit, trifecta
Files
- CHANGELOG.md +4/−0
- LICENSE +27/−0
- Setup.hs +2/−0
- indentation-trifecta.cabal +67/−0
- src/Text/Trifecta/Indentation.hs +185/−0
- tests/ParensTrifecta.hs +109/−0
- tests/all-tests.hs +11/−0
+ CHANGELOG.md view
@@ -0,0 +1,4 @@+# 0.0++* Split `indentation` into separate `indentation-core`, `indentation-parsec` and `indentation-trifecta` packages.+ Keep the original `indentation` for backward compatability and as a general roll-up package.
+ LICENSE view
@@ -0,0 +1,27 @@+Copyright (c) 2014, Michael D. Adams+All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++1. Redistributions of source code must retain the above copyright notice, this+list of conditions and the following disclaimer.++2. Redistributions in binary form must reproduce the above copyright notice,+this list of conditions and the following disclaimer in the documentation+and/or other materials provided with the distribution.++3. Neither the name of the copyright holder nor the names of its contributors+may be used to endorse or promote products derived from this software without+specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ indentation-trifecta.cabal view
@@ -0,0 +1,67 @@+name: indentation-trifecta+version: 0.0+synopsis: Indentation sensitive parsing combinators for Trifecta+description: Indentation sensitive parsing combinators for Trifecta.+ . + See+ .+ __Michael D. Adams and Ömer S. Ağacan__.+ Indentation-sensitive parsing for Parsec.+ In /Proceedings of the 2014 ACM SIGPLAN Symposium on Haskell/,+ Haskell ’14, pages 121–132.+ ACM, New York, NY, USA, September 2014. ISBN 978-1-4503-3041-1.+ <http://dx.doi.org/10.1145/2633357.2633369 doi:10.1145/2633357.2633369>.+ .+ This package provides indentation combinators for+ Trifecta. For Parsec, install+ indentation-parsec. For backward compatability+ or to install both, install indentation.++license: BSD3+license-file: LICENSE+author: Michael D. Adams <http://michaeldadams.org/>+maintainer: Ömer Sinan Ağacan <omeragacan@gmail.com>+ Aleksey Kliger <aleksey@lambdageek.org>+category: Parsing+build-type: Simple+cabal-version: >=1.10+extra-source-files: CHANGELOG.md++homepage: https://bitbucket.org/adamsmd/indentation+bug-reports: https://bitbucket.org/adamsmd/indentation/issues+tested-with: GHC == 7.6.3, GHC == 7.8.4, GHC == 7.10.3, GHC == 8.0.1++source-repository head+ type: git+ location: https://bitbucket.org/adamsmd/indentation.git++library+ hs-source-dirs: src+ build-depends: base >=4.6 && <4.10,+ mtl >=2.1,+ indentation-core == 0.0,+ trifecta >=1.4 && <1.6,+ parsers >=0.10 && <0.13+ exposed-modules: Text.Trifecta.Indentation++ default-language: Haskell2010++ ghc-options: -Wall++test-suite test-indentation+ default-language:+ Haskell2010+ type:+ exitcode-stdio-1.0+ hs-source-dirs:+ tests+ main-is: all-tests.hs+ build-depends:+ trifecta+ other-modules:+ ParensTrifecta+ build-depends:+ base >= 4 && < 5+ , tasty >= 0.10+ , tasty-hunit >= 0.9+ , indentation-trifecta
+ src/Text/Trifecta/Indentation.hs view
@@ -0,0 +1,185 @@+{-# LANGUAGE MultiParamTypeClasses, FlexibleInstances, FlexibleContexts, GeneralizedNewtypeDeriving, StandaloneDeriving #-}++-- Implements "Indentation Senstivie Parsing" for Trifecta+module Text.Trifecta.Indentation (+ I.IndentationRel(..), I.Indentation, I.infIndentation, I.mkIndentationState,+ I.IndentationState,+ IndentationParsing(..),+ Token,+ IndentationParserT,+ runIndentationParserT,+ evalIndentationParserT,+ execIndentationParserT,+ ) where++import Control.Applicative+import Control.Monad.State.Lazy as LazyState+import Control.Monad.State.Strict as StrictState++import Text.Parser.Combinators (Parsing(..))+import Text.Parser.Token (TokenParsing(..))+import Text.Parser.Char (CharParsing(..))+import Text.Parser.LookAhead (LookAheadParsing(..))+import Text.Trifecta.Combinators (DeltaParsing(..), MarkParsing(..))+import Text.Trifecta.Delta (Delta, column)++import Text.Parser.Indentation.Implementation (IndentationState(..), IndentationRel(..), LocalState)+import qualified Text.Parser.Indentation.Implementation as I++--------------+-- User API --+--------------++class IndentationParsing m where+ localTokenMode :: (IndentationRel -> IndentationRel) -> m a -> m a+ localIndentation :: IndentationRel -> m a -> m a+ absoluteIndentation :: m a -> m a+ ignoreAbsoluteIndentation :: m a -> m a+ localAbsoluteIndentation :: m a -> m a+ localAbsoluteIndentation = ignoreAbsoluteIndentation . absoluteIndentation++----------------------+-- Lifted Instances --+----------------------++{- TODO:+Applicative+Functor+MonadWriter w m+MonadError e m+Monad m+MonadReader r m+MonadTrans (StateT s) +Monad m+Monad m+MonadFix m+MonadPlus m+MonadIO m+MonadCont m+#-}++{-# INLINE liftLazyStateT2 #-}+liftLazyStateT2 :: (m (a, s) -> m (a, s)) -> LazyState.StateT s m a -> LazyState.StateT s m a+liftLazyStateT2 f m = LazyState.StateT $ \s -> f (LazyState.runStateT m s)++instance (IndentationParsing i) => IndentationParsing (LazyState.StateT s i) where+ localTokenMode f = liftLazyStateT2 (localTokenMode f)+ localIndentation r = liftLazyStateT2 (localIndentation r)+ absoluteIndentation = liftLazyStateT2 absoluteIndentation+ ignoreAbsoluteIndentation = liftLazyStateT2 ignoreAbsoluteIndentation+ localAbsoluteIndentation = liftLazyStateT2 localAbsoluteIndentation++{-# INLINE liftStrictStateT2 #-}+liftStrictStateT2 :: (m (a, s) -> m (a, s)) -> StrictState.StateT s m a -> StrictState.StateT s m a+liftStrictStateT2 f m = StrictState.StateT $ \s -> f (StrictState.runStateT m s)++instance (IndentationParsing i) => IndentationParsing (StrictState.StateT s i) where+ localTokenMode f = liftStrictStateT2 (localTokenMode f)+ localIndentation r = liftStrictStateT2 (localIndentation r)+ absoluteIndentation = liftStrictStateT2 absoluteIndentation+ ignoreAbsoluteIndentation = liftStrictStateT2 ignoreAbsoluteIndentation+ localAbsoluteIndentation = liftStrictStateT2 localAbsoluteIndentation++---------------+-- Data Type --+---------------++-- TODO: do we need a strict version of this?+newtype IndentationParserT t m a = IndentationParserT { unIndentationParserT :: LazyState.StateT IndentationState m a }+ deriving (Functor, Applicative, Monad, MonadTrans, MonadPlus, Alternative)++deriving instance (Parsing m, MonadPlus m) => Parsing (IndentationParserT t m)+deriving instance (DeltaParsing m) => DeltaParsing (IndentationParserT Char m)+deriving instance (MarkParsing Delta m) => MarkParsing Delta (IndentationParserT Char m)+deriving instance (DeltaParsing m) => DeltaParsing (IndentationParserT Token m)+deriving instance (MarkParsing Delta m) => MarkParsing Delta (IndentationParserT Token m)++{-# INLINE runIndentationParserT #-}+runIndentationParserT :: IndentationParserT t m a -> IndentationState -> m (a, IndentationState)+runIndentationParserT (IndentationParserT m) = LazyState.runStateT m++{-# INLINE evalIndentationParserT #-}+evalIndentationParserT :: (Monad m) => IndentationParserT t m a -> IndentationState -> m a+evalIndentationParserT (IndentationParserT m) = LazyState.evalStateT m++{-# INLINE execIndentationParserT #-}+execIndentationParserT :: (Monad m) => IndentationParserT t m a -> IndentationState -> m IndentationState+execIndentationParserT (IndentationParserT m) = LazyState.execStateT m++---------------------+-- Class Instances --+---------------------++-- Putting the check in CharParsing --++instance (DeltaParsing m) => CharParsing (IndentationParserT Char m) where+ satisfy f = checkIndentation (satisfy f)++instance (DeltaParsing m) => TokenParsing (IndentationParserT Char m) where+ someSpace = IndentationParserT $ someSpace -- Ignore indentation of whitespace++-- Putting the check in TokenParsing --++data Token++instance (DeltaParsing m) => CharParsing (IndentationParserT Token m) where+ satisfy f = IndentationParserT $ satisfy f++instance (DeltaParsing m) => TokenParsing (IndentationParserT Token m) where+ token p = checkIndentation (token (unIndentationParserT p))++--------++instance (LookAheadParsing m, MonadPlus m) => LookAheadParsing (IndentationParserT t m) where+ lookAhead m = IndentationParserT $ do+ s <- get+ x <- lookAhead (unIndentationParserT m)+ put s+ return x++--------++instance (Monad m) => IndentationParsing (IndentationParserT t m) where+ {-# INLINE localTokenMode #-}+ localTokenMode = I.localTokenMode localState++ {-# INLINE localIndentation #-}+ localIndentation = I.localIndentation localStateUnlessAbsMode++ {-# INLINE absoluteIndentation #-}+ absoluteIndentation = I.absoluteIndentation localState++ {-# INLINE ignoreAbsoluteIndentation #-}+ ignoreAbsoluteIndentation = I.ignoreAbsoluteIndentation localState++ {-# INLINE localAbsoluteIndentation #-}+ localAbsoluteIndentation = I.localAbsoluteIndentation localState++---------------------+-- Private Helpers --+---------------------++{-# INLINE localState #-}+localState :: (Monad m) => LocalState (IndentationParserT t m a)+localState pre post m = IndentationParserT $ do+ is <- get+ put (pre is)+ x <- unIndentationParserT m+ is' <- get+ put (post is is')+ return x++{-# INLINE localStateUnlessAbsMode #-}+localStateUnlessAbsMode :: (Monad m) => LocalState (IndentationParserT t m a)+localStateUnlessAbsMode pre post m = IndentationParserT $ do+ a <- gets I.indentationStateAbsMode+ unIndentationParserT $ if a then m else localState pre post m++{-# INLINE checkIndentation #-}+checkIndentation :: (DeltaParsing m) => LazyState.StateT IndentationState m a -> IndentationParserT t m a+checkIndentation m = IndentationParserT $ do+ is <- get+ p <- position+ let ok is' = do x <- m; put is'; return x+ err msg = fail msg+ I.updateIndentation is (fromIntegral $ column p + 1) ok err
+ tests/ParensTrifecta.hs view
@@ -0,0 +1,109 @@+module ParensTrifecta where++import Data.Monoid (Monoid(..))+import Control.Applicative++import Test.Tasty (TestTree, testGroup)+import Test.Tasty.HUnit (testCase, assertEqual, assertFailure, Assertion)++import Text.Trifecta+import Text.Trifecta.Indentation++data A+ = Par A -- '(' A ')'+ | Bra A -- '[' A ']'+ | Seq A A -- A A+ | Nil -- epsilon+ deriving (Show, Eq)++-- a :: (Monad m, Stream s m (Char, Indentation)) => ParsecT (IndentStream s) () m A+a :: (Applicative m, TokenParsing m, IndentationParsing m) => m A+a = choice [ Seq <$> a' <*> a, a', pure Nil ]++-- a' :: (Monad m, Stream s m (Char, Indentation)) => ParsecT (IndentStream s) () m A+a' :: (TokenParsing m, IndentationParsing m) => m A+a' = choice+ [ Par <$>+ between (localTokenMode (const Eq) $ symbolic '(')+ (localTokenMode (const Eq) $ symbolic ')')+ (localIndentation Gt a)+ , Bra <$>+ between (localTokenMode (const Ge) $ symbolic '[')+ (localTokenMode (const Ge) $ symbolic ']')+ (localIndentation Gt a)+ ]+++evalCharIndentationParserT :: Monad m => IndentationParserT Char m a -> IndentationState -> m a+evalCharIndentationParserT = evalIndentationParserT++evalTokenIndentationParserT :: Monad m => IndentationParserT Token m a -> IndentationState -> m a+evalTokenIndentationParserT = evalIndentationParserT++runParse ev input+ = let indA = ev a $ mkIndentationState 0 infIndentation True Gt+ in case parseString indA mempty input of+ Failure err -> Left (show err)+ Success a -> Right a++runCharParse = runParse evalCharIndentationParserT+runTokenParse = runParse evalTokenIndentationParserT++-- conveniences for tests+parL = Par . listToSeq+braL = Bra . listToSeq++listToSeq [] = Nil+listToSeq (x:xs) = Seq x $ listToSeq xs++input1 = unlines [ "("+ , " [("+ , " )"+ , " ]"+ , ")"+ ]+output1c = runCharParse input1+output1t = runTokenParse input1+expected1 = listToSeq [ parL [braL [parL []]]+ ]++input2 = unlines [ "("+ , " ["+ , " ("+ , " )"+ , " []"+ , " ]"+ , " ("+ , " )"+ , ")"+ ]+output2c = runCharParse input2+output2t = runTokenParse input2+expected2 = listToSeq [ parL [ braL [ parL []+ , braL []+ ]+ , parL []+ ]+ ]+++assertParsedOk :: (Show err, Show a, Eq a) => Either err a -> a -> Assertion+assertParsedOk actual expected =+ case actual of+ Right ok -> assertEqual "parsing succeeded, but " expected ok+ Left err -> assertFailure ("parse failed with " ++ show err+ ++ ", expected " ++ show expected)++allTests :: TestTree+allTests =+ testGroup "parens (trifecta)"+ [+ testGroup "char parsing"+ [ testCase "1" $ assertParsedOk output1c expected1+ , testCase "2" $ assertParsedOk output2c expected2+ ]+ , testGroup "token parsing"+ [ testCase "1" $ assertParsedOk output1t expected1+ , testCase "2" $ assertParsedOk output2t expected2+ ]+ ]
+ tests/all-tests.hs view
@@ -0,0 +1,11 @@+{-# LANGUAGE CPP #-}+module Main where++import Test.Tasty (defaultMain, testGroup)+import qualified ParensTrifecta++main =+ defaultMain $ testGroup "All tests" $+ [+ ParensTrifecta.allTests+ ]