indentation 0.2.1.2 → 0.3
raw patch · 17 files changed
+45/−1556 lines, 17 filesdep +indentation-coredep +indentation-parsecdep +indentation-trifectadep −indentationdep −tastydep −tasty-hunitdep ~basedep ~parsecdep ~trifectaPVP ok
version bump matches the API change (PVP)
Dependencies added: indentation-core, indentation-parsec, indentation-trifecta
Dependencies removed: indentation, tasty, tasty-hunit
Dependency ranges changed: base, parsec, trifecta
API changes (from Hackage documentation)
- Text.Parsec.Indentation: Any :: IndentationRel
- Text.Parsec.Indentation: Const :: Indentation -> IndentationRel
- Text.Parsec.Indentation: Eq :: IndentationRel
- Text.Parsec.Indentation: Ge :: IndentationRel
- Text.Parsec.Indentation: Gt :: IndentationRel
- Text.Parsec.Indentation: IndentStream :: !IndentationState -> !s -> IndentStream s
- Text.Parsec.Indentation: [indentationState] :: IndentStream s -> !IndentationState
- Text.Parsec.Indentation: [tokenStream] :: IndentStream s -> !s
- Text.Parsec.Indentation: absoluteIndentation :: (Monad m) => ParsecT (IndentStream s) u m a -> ParsecT (IndentStream s) u m a
- Text.Parsec.Indentation: consumed :: (Monad m) => (a -> m b) -> (a -> m b) -> Consumed (m a) -> m b
- Text.Parsec.Indentation: data IndentStream s
- Text.Parsec.Indentation: data IndentationRel
- Text.Parsec.Indentation: ignoreAbsoluteIndentation :: (Monad m) => ParsecT (IndentStream s) u m a -> ParsecT (IndentStream s) u m a
- Text.Parsec.Indentation: indentStreamParser :: (Monad m) => ParsecT s u m (t, Indentation) -> ParsecT (IndentStream s) u m (IndentationToken t)
- Text.Parsec.Indentation: infIndentation :: Indentation
- Text.Parsec.Indentation: instance (GHC.Base.Monad m, Text.Parsec.Prim.Stream s m (t, Text.Parser.Indentation.Implementation.Indentation)) => Text.Parsec.Prim.Stream (Text.Parsec.Indentation.IndentStream s) m (Text.Parsec.Indentation.IndentationToken t)
- Text.Parsec.Indentation: instance GHC.Show.Show s => GHC.Show.Show (Text.Parsec.Indentation.IndentStream s)
- Text.Parsec.Indentation: localAbsoluteIndentation :: (Monad m) => ParsecT (IndentStream s) u m a -> ParsecT (IndentStream s) u m a
- Text.Parsec.Indentation: localIndentation :: (Monad m) => IndentationRel -> ParsecT (IndentStream s) u m a -> ParsecT (IndentStream s) u m a
- Text.Parsec.Indentation: localState :: (Monad m) => LocalState (ParsecT (IndentStream s) u m a)
- Text.Parsec.Indentation: localStateUnlessAbsMode :: (Monad m) => LocalState (ParsecT (IndentStream s) u m a)
- Text.Parsec.Indentation: localTokenMode :: (Monad m) => (IndentationRel -> IndentationRel) -> ParsecT (IndentStream s) u m a -> ParsecT (IndentStream s) u m a
- Text.Parsec.Indentation: mkIndentStream :: Indentation -> Indentation -> Bool -> IndentationRel -> s -> IndentStream s
- Text.Parsec.Indentation: streamToList :: (Monad m, Stream s m t) => s -> m [t]
- Text.Parsec.Indentation: type Indentation = Int
- Text.Parsec.Indentation: type IndentationToken t = t
- Text.Parsec.Indentation.Char: CharIndentStream :: {-# UNPACK #-} !Indentation -> !s -> CharIndentStream s
- Text.Parsec.Indentation.Char: [charIndentStreamColumn] :: CharIndentStream s -> {-# UNPACK #-} !Indentation
- Text.Parsec.Indentation.Char: [charIndentStreamStream] :: CharIndentStream s -> !s
- Text.Parsec.Indentation.Char: charIndentStreamParser :: (Monad m) => ParsecT s u m t -> ParsecT (CharIndentStream s) u m (t, Indentation)
- Text.Parsec.Indentation.Char: consumed :: (Monad m) => (a -> m b) -> (a -> m b) -> Consumed (m a) -> m b
- Text.Parsec.Indentation.Char: data CharIndentStream s
- Text.Parsec.Indentation.Char: instance GHC.Show.Show s => GHC.Show.Show (Text.Parsec.Indentation.Char.CharIndentStream s)
- Text.Parsec.Indentation.Char: instance Text.Parsec.Prim.Stream s m GHC.Types.Char => Text.Parsec.Prim.Stream (Text.Parsec.Indentation.Char.CharIndentStream s) m (GHC.Types.Char, Text.Parser.Indentation.Implementation.Indentation)
- Text.Parsec.Indentation.Char: mkCharIndentStream :: s -> CharIndentStream s
- Text.Parsec.Indentation.Char: updateColumn :: Integral a => a -> Char -> a
- Text.Parsec.Indentation.Token: makeIndentLanguageDef :: (Monad m) => GenLanguageDef s st m -> GenLanguageDef (IndentStream (CharIndentStream s)) st m
- Text.Parsec.Indentation.Token: makeTokenParser :: (Stream s m (Char, Indentation)) => GenLanguageDef (IndentStream s) u m -> GenTokenParser (IndentStream s) u m
- Text.Parsec.Indentation.Token: type IndentLanguageDef st = GenLanguageDef (IndentStream (CharIndentStream String)) st Identity
- Text.Parser.Indentation.Implementation: Any :: IndentationRel
- Text.Parser.Indentation.Implementation: Const :: Indentation -> IndentationRel
- Text.Parser.Indentation.Implementation: Eq :: IndentationRel
- Text.Parser.Indentation.Implementation: Ge :: IndentationRel
- Text.Parser.Indentation.Implementation: Gt :: IndentationRel
- Text.Parser.Indentation.Implementation: IndentationState :: {-# UNPACK #-} !Indentation -> {-# UNPACK #-} !Indentation -> !Bool -> !IndentationRel -> IndentationState
- Text.Parser.Indentation.Implementation: [absMode] :: IndentationState -> !Bool
- Text.Parser.Indentation.Implementation: [maxIndentation] :: IndentationState -> {-# UNPACK #-} !Indentation
- Text.Parser.Indentation.Implementation: [minIndentation] :: IndentationState -> {-# UNPACK #-} !Indentation
- Text.Parser.Indentation.Implementation: [tokenRel] :: IndentationState -> !IndentationRel
- Text.Parser.Indentation.Implementation: absoluteIndentation :: LocalState a -> a -> a
- Text.Parser.Indentation.Implementation: data IndentationRel
- Text.Parser.Indentation.Implementation: data IndentationState
- Text.Parser.Indentation.Implementation: ignoreAbsoluteIndentation :: LocalState a -> a -> a
- Text.Parser.Indentation.Implementation: indentationStateAbsMode :: IndentationState -> Bool
- Text.Parser.Indentation.Implementation: infIndentation :: Indentation
- Text.Parser.Indentation.Implementation: instance GHC.Classes.Eq Text.Parser.Indentation.Implementation.IndentationRel
- Text.Parser.Indentation.Implementation: instance GHC.Show.Show Text.Parser.Indentation.Implementation.IndentationRel
- Text.Parser.Indentation.Implementation: instance GHC.Show.Show Text.Parser.Indentation.Implementation.IndentationState
- Text.Parser.Indentation.Implementation: localAbsoluteIndentation :: LocalState a -> a -> a
- Text.Parser.Indentation.Implementation: localIndentation :: LocalState a -> IndentationRel -> a -> a
- Text.Parser.Indentation.Implementation: localIndentation' :: LocalState a -> (Indentation -> Indentation) -> (Indentation -> Indentation) -> (Indentation -> Indentation -> Indentation) -> a -> a
- Text.Parser.Indentation.Implementation: localTokenMode :: (LocalState a) -> (IndentationRel -> IndentationRel) -> a -> a
- Text.Parser.Indentation.Implementation: mkIndentationState :: Indentation -> Indentation -> Bool -> IndentationRel -> IndentationState
- Text.Parser.Indentation.Implementation: type Indentation = Int
- Text.Parser.Indentation.Implementation: type LocalState a = (IndentationState -> IndentationState) -> (IndentationState -> IndentationState -> IndentationState) -> a -> a
- Text.Parser.Indentation.Implementation: updateIndentation :: IndentationState -> Indentation -> (IndentationState -> a) -> (String -> a) -> a
- Text.Parser.Indentation.Implementation: updateIndentation' :: Indentation -> Indentation -> IndentationRel -> Indentation -> (Indentation -> Indentation -> a) -> (String -> a) -> a
- Text.Trifecta.Indentation: Any :: IndentationRel
- Text.Trifecta.Indentation: Const :: Indentation -> IndentationRel
- Text.Trifecta.Indentation: Eq :: IndentationRel
- Text.Trifecta.Indentation: Ge :: IndentationRel
- Text.Trifecta.Indentation: Gt :: IndentationRel
- Text.Trifecta.Indentation: absoluteIndentation :: IndentationParsing m => m a -> m a
- Text.Trifecta.Indentation: class IndentationParsing m where localAbsoluteIndentation = ignoreAbsoluteIndentation . absoluteIndentation
- Text.Trifecta.Indentation: data IndentationParserT t m a
- Text.Trifecta.Indentation: data IndentationRel
- Text.Trifecta.Indentation: data IndentationState
- Text.Trifecta.Indentation: data Token
- Text.Trifecta.Indentation: evalIndentationParserT :: (Monad m) => IndentationParserT t m a -> IndentationState -> m a
- Text.Trifecta.Indentation: execIndentationParserT :: (Monad m) => IndentationParserT t m a -> IndentationState -> m IndentationState
- Text.Trifecta.Indentation: ignoreAbsoluteIndentation :: IndentationParsing m => m a -> m a
- Text.Trifecta.Indentation: infIndentation :: Indentation
- Text.Trifecta.Indentation: instance (Text.Parser.Combinators.Parsing m, GHC.Base.MonadPlus m) => Text.Parser.Combinators.Parsing (Text.Trifecta.Indentation.IndentationParserT t m)
- Text.Trifecta.Indentation: instance (Text.Parser.LookAhead.LookAheadParsing m, GHC.Base.MonadPlus m) => Text.Parser.LookAhead.LookAheadParsing (Text.Trifecta.Indentation.IndentationParserT t m)
- Text.Trifecta.Indentation: instance Control.Monad.Trans.Class.MonadTrans (Text.Trifecta.Indentation.IndentationParserT t)
- Text.Trifecta.Indentation: instance GHC.Base.Functor m => GHC.Base.Functor (Text.Trifecta.Indentation.IndentationParserT t m)
- Text.Trifecta.Indentation: instance GHC.Base.Monad m => GHC.Base.Applicative (Text.Trifecta.Indentation.IndentationParserT t m)
- Text.Trifecta.Indentation: instance GHC.Base.Monad m => GHC.Base.Monad (Text.Trifecta.Indentation.IndentationParserT t m)
- Text.Trifecta.Indentation: instance GHC.Base.Monad m => Text.Trifecta.Indentation.IndentationParsing (Text.Trifecta.Indentation.IndentationParserT t m)
- Text.Trifecta.Indentation: instance GHC.Base.MonadPlus m => GHC.Base.Alternative (Text.Trifecta.Indentation.IndentationParserT t m)
- Text.Trifecta.Indentation: instance GHC.Base.MonadPlus m => GHC.Base.MonadPlus (Text.Trifecta.Indentation.IndentationParserT t m)
- Text.Trifecta.Indentation: instance Text.Trifecta.Combinators.DeltaParsing m => Text.Parser.Char.CharParsing (Text.Trifecta.Indentation.IndentationParserT GHC.Types.Char m)
- Text.Trifecta.Indentation: instance Text.Trifecta.Combinators.DeltaParsing m => Text.Parser.Char.CharParsing (Text.Trifecta.Indentation.IndentationParserT Text.Trifecta.Indentation.Token m)
- Text.Trifecta.Indentation: instance Text.Trifecta.Combinators.DeltaParsing m => Text.Parser.Token.TokenParsing (Text.Trifecta.Indentation.IndentationParserT GHC.Types.Char m)
- Text.Trifecta.Indentation: instance Text.Trifecta.Combinators.DeltaParsing m => Text.Parser.Token.TokenParsing (Text.Trifecta.Indentation.IndentationParserT Text.Trifecta.Indentation.Token m)
- Text.Trifecta.Indentation: instance Text.Trifecta.Combinators.DeltaParsing m => Text.Trifecta.Combinators.DeltaParsing (Text.Trifecta.Indentation.IndentationParserT GHC.Types.Char m)
- Text.Trifecta.Indentation: instance Text.Trifecta.Combinators.DeltaParsing m => Text.Trifecta.Combinators.DeltaParsing (Text.Trifecta.Indentation.IndentationParserT Text.Trifecta.Indentation.Token m)
- Text.Trifecta.Indentation: instance Text.Trifecta.Combinators.MarkParsing Text.Trifecta.Delta.Delta m => Text.Trifecta.Combinators.MarkParsing Text.Trifecta.Delta.Delta (Text.Trifecta.Indentation.IndentationParserT GHC.Types.Char m)
- Text.Trifecta.Indentation: instance Text.Trifecta.Combinators.MarkParsing Text.Trifecta.Delta.Delta m => Text.Trifecta.Combinators.MarkParsing Text.Trifecta.Delta.Delta (Text.Trifecta.Indentation.IndentationParserT Text.Trifecta.Indentation.Token m)
- Text.Trifecta.Indentation: instance Text.Trifecta.Indentation.IndentationParsing i => Text.Trifecta.Indentation.IndentationParsing (Control.Monad.Trans.State.Lazy.StateT s i)
- Text.Trifecta.Indentation: instance Text.Trifecta.Indentation.IndentationParsing i => Text.Trifecta.Indentation.IndentationParsing (Control.Monad.Trans.State.Strict.StateT s i)
- Text.Trifecta.Indentation: localAbsoluteIndentation :: IndentationParsing m => m a -> m a
- Text.Trifecta.Indentation: localIndentation :: IndentationParsing m => IndentationRel -> m a -> m a
- Text.Trifecta.Indentation: localTokenMode :: IndentationParsing m => (IndentationRel -> IndentationRel) -> m a -> m a
- Text.Trifecta.Indentation: mkIndentationState :: Indentation -> Indentation -> Bool -> IndentationRel -> IndentationState
- Text.Trifecta.Indentation: runIndentationParserT :: IndentationParserT t m a -> IndentationState -> m (a, IndentationState)
- Text.Trifecta.Indentation: type Indentation = Int
Files
- CHANGELOG.md +5/−0
- Text/Parsec/Indentation.hs +0/−209
- Text/Parsec/Indentation/Char.hs +0/−47
- Text/Parsec/Indentation/Examples/ISWIM.hs +0/−61
- Text/Parsec/Indentation/Examples/Parens.hs +0/−58
- Text/Parsec/Indentation/Token.hs +0/−400
- Text/Parser/Indentation/Implementation.hs +0/−338
- Text/Trifecta/Indentation.hs +0/−185
- indentation.cabal +18/−36
- src/Text/Parsec/Indentation.hs +4/−0
- src/Text/Parsec/Indentation/Char.hs +4/−0
- src/Text/Parsec/Indentation/Token.hs +4/−0
- src/Text/Parser/Indentation/Implementation.hs +6/−0
- src/Text/Trifecta/Indentation.hs +4/−0
- tests/ParensParsec.hs +0/−86
- tests/ParensTrifecta.hs +0/−109
- tests/all-tests.hs +0/−27
CHANGELOG.md view
@@ -1,3 +1,8 @@+# 0.3 #++* Broke package up into `indentation-core`, `indentation-parsec` and `indentation-trifecta` packages.+ This package is now solely for backward compatability.+ # 0.2.1.2 # * Support GHC 8.0.1 (release candidate 2)
− Text/Parsec/Indentation.hs
@@ -1,209 +0,0 @@-{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses, FlexibleContexts, UndecidableInstances, TupleSections #-}-{-# OPTIONS -Wall #-}-module Text.Parsec.Indentation (module Text.Parsec.Indentation, I.IndentationRel(..), Indentation, infIndentation) where---- Implements "Indentation Senstivie Parising: Landin Revisited"------ Primary functions are:--- - 'localIndent':--- - 'absoluteIndent':--- - 'localTokenMode':------ Primary driver functions are:--- - TODO---- TODO:--- Grace style indentation stream--import Control.Monad---import Text.Parsec.Prim-import Text.Parsec.Prim (ParsecT, mkPT, runParsecT,- Stream(..), Consumed(..), Reply(..),- State(..), getInput, setInput)-import Text.Parsec.Error (Message (Message), addErrorMessage)-import Text.Parser.Indentation.Implementation as I----------------------------- Indentable Stream---------------------------data IndentStream s = IndentStream { indentationState :: !IndentationState, tokenStream :: !s } deriving (Show)---data IndentationToken t = IndentationToken !t | InvalidIndentation String-type IndentationToken t = t--{-# INLINE mkIndentStream #-}-mkIndentStream :: Indentation -> Indentation -> Bool -> IndentationRel -> s -> IndentStream s-mkIndentStream lo hi mode rel s = IndentStream (mkIndentationState lo hi mode rel) s--instance (Monad m, Stream s m (t, Indentation)) => Stream (IndentStream s) m (IndentationToken t) where- uncons (IndentStream is s) = do- x <- uncons s- case x of- Nothing -> return Nothing- Just ((t, i), s') -> return $ updateIndentation is i ok err where- ok is' = Just ({-IndentationToken-} t, IndentStream is' s')- err _ = Nothing --(InvalidIndentation msg, IndentStream is s)- -- HACK: Sigh! We have no way to properly signal the- -- sort of failure that occurs here. We would do 'fail- -- "Invalid indentation. "++msg', but that triggers a- -- non-backtracking error. 'return Nothing' will make- -- Parsec think the stream is empty (which is wrong),- -- but at least it is a backtracking error. The- -- fundamental problem is that 'm' *not* ParsecT (where- -- we could signal a parsing error) but is whatever- -- monad 'm' happens to be the argument to ParsecT.--{-# INLINE localState #-}-localState :: (Monad m) => LocalState (ParsecT (IndentStream s) u m a)-localState pre post m = do- IndentStream is s <- getInput- setInput (IndentStream (pre is) s)- x <- m- IndentStream is' s' <- getInput- setInput (IndentStream (post is is') s')- return x--{-# INLINE localStateUnlessAbsMode #-}-localStateUnlessAbsMode :: (Monad m) => LocalState (ParsecT (IndentStream s) u m a)-localStateUnlessAbsMode pre post m = do- a <- liftM (indentationStateAbsMode . indentationState) getInput- if a then m else localState pre post m------------------------------ Operations---------------------------{-# INLINE localTokenMode #-}-localTokenMode :: (Monad m) => (IndentationRel -> IndentationRel) -> ParsecT (IndentStream s) u m a -> ParsecT (IndentStream s) u m a-localTokenMode = I.localTokenMode localState--{-# INLINE localIndentation #-}-localIndentation :: (Monad m) => IndentationRel -> ParsecT (IndentStream s) u m a -> ParsecT (IndentStream s) u m a-localIndentation = I.localIndentation localStateUnlessAbsMode--{-# INLINE absoluteIndentation #-}-absoluteIndentation :: (Monad m) => ParsecT (IndentStream s) u m a -> ParsecT (IndentStream s) u m a-absoluteIndentation = I.absoluteIndentation localState--- post _ i2 = when (absMode i2) (fail "absoluteIndent: no tokens consumed") >>--{-# INLINE ignoreAbsoluteIndentation #-}-ignoreAbsoluteIndentation :: (Monad m) => ParsecT (IndentStream s) u m a -> ParsecT (IndentStream s) u m a-ignoreAbsoluteIndentation = I.ignoreAbsoluteIndentation localState--{-# INLINE localAbsoluteIndentation #-}-localAbsoluteIndentation :: (Monad m) => ParsecT (IndentStream s) u m a -> ParsecT (IndentStream s) u m a-localAbsoluteIndentation = I.localAbsoluteIndentation localState----------------------------- Indent Stream Impls---------------------------streamToList :: (Monad m, Stream s m t) => s -> m [t]-streamToList s = do- x <- uncons s- case x of- Nothing -> return []- Just (c, s') -> do s'' <- streamToList s'- return (c : s'')--------------------- SourcePos--{--mkSourcePosIndentStream s = SourcePosIndentStream s-newtype SourcePosIndentStream s = SourcePosIndentStream s-instance (Stream s m t) => Stream (SourcePosIndentStream s) m (Indent, t) where- uncons (SourcePosIndentStream s) = do- col <- liftM sourceColumn $ getPosition- x <- uncons s- case x of- Nothing -> return Nothing- Just x -> return (Just ((col, x), SourcePosIndentStream s))--}---------------------- TODO: parser based on first non-whitespace char--------------------- First token of line indents--------------------- Based on Indents---- Note that if 'p' consumes input but is at the wrong indentation, then--- 'indentStreamParser p' signals an error but does *not* consume input.--- This allows Parsec primitives like 'string' to be properly backtracked.-{-# INLINE indentStreamParser #-}-indentStreamParser :: (Monad m) => ParsecT s u m (t, Indentation) -> ParsecT (IndentStream s) u m (IndentationToken t)-indentStreamParser p = mkPT $ \state ->- let IndentStream is s = stateInput state- go f (Ok (a, i) state' e) = updateIndentation is i ok err where- ok is' = return $ f $ return (Ok ({-IndentationToken-} a) (state' {stateInput = IndentStream is' (stateInput state') }) e)- err msg = return $ Empty $ return $ Error (Message ("Invalid indentation. "++msg++show ((stateInput state) { tokenStream = ""})) `addErrorMessage` e)- go f (Error e) = return $ f $ return (Error e)- in runParsecT p (state { stateInput = s }) >>= consumed (go Consumed) (go Empty)--{-# INLINE consumed #-}-consumed :: (Monad m) => (a -> m b) -> (a -> m b) -> Consumed (m a) -> m b-consumed c _ (Consumed m) = m >>= c-consumed _ e (Empty m) = m >>= e---- lifting operator--- token, tokens, tokenPrim, tokenPrimEx ???--- whiteSpace--- ByteString--- ByteString.Lazy--- Text--{--delimitedLayout :: Stream (IndentStream s) m t =>- ParsecT (IndentStream s) u m open -> Bool ->- ParsecT (IndentStream s) u m close -> Bool ->- ParsecT (IndentStream s) u m a -> ParsecT (IndentStream s) u m a-delimitedLayout open openAny close closeAny body = between open' close' (localIndent (Const 0) body) where- open' | openAny = localIndent (Const 0) open- | otherwise = open- close' | closeAny = localIndent (Const 0) close- | otherwise = close--indentedLayout :: Stream (IndentStream s) m t =>- (Maybe (ParsecT (IndentStream s) u m sep)) ->- ParsecT (IndentStream s) u m a -> ParsecT (IndentStream s) u m [a]-indentedLayout (Nothing ) clause = localIndent Gt $ many $ absoluteIndent $ clause-indentedLayout (Just sep) clause = liftM concat $ localIndent Gt $ many $ absoluteIndent $ sepBy1 clause sep--}--{--layout p = delimitedLayout (symbol "{") False (symbol "}") True (semiSep p)- <|> indentedLayout (Just semi) p--identifier pred = liftM fromString $ try $ identifier >>= \x -> guard (pred x) >> return x-operator pred = liftM fromString $ try $ operator >>= \x -> guard (pred x) >> return x--reserved name = (if name `elem` middleKeywords then localFirstTokenMode (const Ge) else id) $ reserved name--Numbers, Integers and Naturals are custom--dotSep-dotSep1---}--{--test :: String-test = foo where- foo = "abc \-\def" ++ ""--test2 :: Int-test2 = foo where- foo = let { x = 1;- } in x------ All code indented?- foo = 3- bar = 4--}
− Text/Parsec/Indentation/Char.hs
@@ -1,47 +0,0 @@-{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses, FlexibleContexts #-}-module Text.Parsec.Indentation.Char where--import Text.Parsec.Prim (ParsecT, mkPT, runParsecT,- Stream(..),- Consumed(..), Reply(..),- State(..))-import Text.Parsec.Pos (sourceColumn)-import Text.Parser.Indentation.Implementation (Indentation)--------------------- Unicode char--- newtype UnicodeIndentStream--------------------- Based on Char-{-# INLINE mkCharIndentStream #-}-mkCharIndentStream :: s -> CharIndentStream s-mkCharIndentStream s = CharIndentStream 1 s-data CharIndentStream s = CharIndentStream { charIndentStreamColumn :: {-# UNPACK #-} !Indentation,- charIndentStreamStream :: !s } deriving (Show)--instance (Stream s m Char) => Stream (CharIndentStream s) m (Char, Indentation) where- uncons (CharIndentStream i s) = do- x <- uncons s- case x of- Nothing -> return Nothing- Just (c, cs) -> return (Just ((c, i), CharIndentStream (updateColumn i c) cs))--{-# INLINE updateColumn #-}-updateColumn :: Integral a => a -> Char -> a-updateColumn _ '\n' = 1-updateColumn i '\t' = i + 8 - ((i-1) `mod` 8)-updateColumn i _ = i + 1--{-# INLINE charIndentStreamParser #-}-charIndentStreamParser :: (Monad m) => ParsecT s u m t -> ParsecT (CharIndentStream s) u m (t, Indentation)-charIndentStreamParser p = mkPT $ \state ->- let go (Ok a state' e) = return (Ok (a, sourceColumn $ statePos state) (state' { stateInput = CharIndentStream (sourceColumn $ statePos state') (stateInput state') }) e)- go (Error e) = return (Error e)- in runParsecT p (state { stateInput = charIndentStreamStream (stateInput state) })- >>= consumed (return . Consumed . go) (return . Empty . go)--{-# INLINE consumed #-}-consumed :: (Monad m) => (a -> m b) -> (a -> m b) -> Consumed (m a) -> m b-consumed c _ (Consumed m) = m >>= c-consumed _ e (Empty m) = m >>= e
− Text/Parsec/Indentation/Examples/ISWIM.hs
@@ -1,61 +0,0 @@-module Text.Parsec.Indentation.Examples.ISWIM where---- Encodes example TODO from the paper TODO.--- Note that because Parsec doesn't support full backtracking--- this-----import Control.Applicative ((<$>))-import Text.Parsec-import Text.Parsec.Indentation-import Text.Parsec.Indentation.Char--data ID = ID String deriving (Show, Eq)-data Expr- = Where Expr ID Expr -- expr -> expr 'where' ID '=' |expr|>=- | Plus Expr Expr -- expr -> expr '+' expr- | Minus Expr -- expr -> '-' expr- | Parens Expr -- expr -> '(' expr* ')'- | Var ID -- expr -> ID- deriving (Show, Eq)--runParse :: String -> Either ParseError Expr-runParse input- = case runParser expr () "" (mkIndentStream 0 infIndentation True Ge (mkCharIndentStream input)) of- Left err -> Left err- Right a -> Right a---- Note that this grammar DOES NOT WORK as written because it contains--- a left recursion. (It diverges.) However, it provides a good--- first example to see how to use the combinators in--- Text.Parsec.Indentation.--tok s = string s >> localTokenMode (const Any) (ignoreAbsoluteIndentation (many (char ' ' <|> char '\n')))-ident = choice (map f ["v", "w", "x", "y", "z"])- where f x = tok x >> return (ID x)--expr = choice $ map try- [ do e1 <- expr_nonrec- tok "where"- i <- ident- tok "="- e2 <- localIndentation Ge (absoluteIndentation expr)- return (Where e1 i e2)- , do e1 <- expr_nonrec- tok "+"- e2 <- expr- return (Plus e1 e2)- , expr_nonrec- ]--expr_nonrec = choice- [ tok "-" >> (Minus <$> expr)- , Parens <$> between (tok "(") (tok ")") (localIndentation Any expr)- , Var <$> ident- ]---input1 = "x + v where\n\- \ x = -(\n\- \y + z) + w"-output1 = runParse input1
− Text/Parsec/Indentation/Examples/Parens.hs
@@ -1,58 +0,0 @@-{-# LANGUAGE NoMonomorphismRestriction, FlexibleContexts #-}-module Text.Parsec.Indentation.Examples.Parens where---- Encodes example TODO from the paper TODO.--- Note that because Parsec doesn't support full backtracking--- this--import Control.Applicative-import Text.Parsec-import Text.Parsec.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 = choice [ Seq <$> a' <*> a, a', return Nil ]--a' :: (Monad m, Stream s m (Char, Indentation)) => ParsecT (IndentStream s) () m A-a' = choice- [ Par <$>- between (localTokenMode (const Eq) $ char '(')- (localTokenMode (const Eq) $ char ')')- (localIndentation Gt a)- , Bra <$>- between (localTokenMode (const Ge) $ char '[')- (localTokenMode (const Ge) $ char ']')- (localIndentation Gt a)- ]---runParse input- = case runParser a () "" (mkIndentStream 0 infIndentation True Gt input) of- Left err -> Left (show err)- Right a -> Right a--input1 = [('(', 1),- ('[', 4),- ('(', 5),- (')', 5),- (']', 7),- (')', 1)]-output1 = runParse input1--input2 = [('(', 1),- ('[', 8),- ('(', 6),- (')', 6),- ('[', 8),- (']', 9),- (']', 4),- ('(', 3),- (')', 3),- (')', 1)]-output2 = runParse input2
− Text/Parsec/Indentation/Token.hs
@@ -1,400 +0,0 @@-{-# LANGUAGE FlexibleContexts, NoMonomorphismRestriction #-}-{-# OPTIONS -Wall -fno-warn-unused-do-bind -fno-warn-name-shadowing #-}-module Text.Parsec.Indentation.Token where--import Control.Monad.Identity-import Data.Char-import Data.List (nub, sort)-import Text.Parsec-import Text.Parsec.Token--import Text.Parsec.Indentation-import Text.Parsec.Indentation.Char (CharIndentStream(..), charIndentStreamParser)--type IndentLanguageDef st = GenLanguageDef (IndentStream (CharIndentStream String)) st Identity--makeIndentLanguageDef :: (Monad m) => GenLanguageDef s st m -> GenLanguageDef (IndentStream (CharIndentStream s)) st m-makeIndentLanguageDef l = l {- identStart = indentStreamParser (charIndentStreamParser (identStart l)),- identLetter = indentStreamParser (charIndentStreamParser (identLetter l)),- opStart = indentStreamParser (charIndentStreamParser (opStart l)),- opLetter = indentStreamParser (charIndentStreamParser (opLetter l))- }---- TODO: makeTokenParser :: (Stream (IndentStream s) m Char)-makeTokenParser :: (Stream s m (Char, Indentation))- => GenLanguageDef (IndentStream s) u m -> GenTokenParser (IndentStream s) u m-makeTokenParser languageDef- = TokenParser{ identifier = identifier- , reserved = reserved- , operator = operator- , reservedOp = reservedOp-- , charLiteral = charLiteral- , stringLiteral = stringLiteral- , natural = natural- , integer = integer- , float = float- , naturalOrFloat = naturalOrFloat- , decimal = decimal- , hexadecimal = hexadecimal- , octal = octal-- , symbol = symbol- , lexeme = lexeme- , whiteSpace = whiteSpace- , parens = parens- , braces = braces- , angles = angles- , brackets = brackets- , squares = brackets- , semi = semi- , comma = comma- , colon = colon- , dot = dot- , semiSep = semiSep- , semiSep1 = semiSep1- , commaSep = commaSep- , commaSep1 = commaSep1- }- where-- ------------------------------------------------------------ -- Bracketing- ------------------------------------------------------------ parens p = between (symbol "(") (symbol ")") p- braces p = between (symbol "{") (symbol "}") p- angles p = between (symbol "<") (symbol ">") p- brackets p = between (symbol "[") (symbol "]") p-- semi = symbol ";"- comma = symbol ","- dot = symbol "."- colon = symbol ":"-- commaSep p = sepBy p comma- semiSep p = sepBy p semi-- commaSep1 p = sepBy1 p comma- semiSep1 p = sepBy1 p semi--- ------------------------------------------------------------ -- Chars & Strings- ------------------------------------------------------------ charLiteral = lexeme (between (char '\'')- (char '\'' <?> "end of character")- characterChar )- <?> "character"-- characterChar = charLetter <|> charEscape- <?> "literal character"-- charEscape = do{ char '\\'; escapeCode }- charLetter = satisfy (\c -> (c /= '\'') && (c /= '\\') && (c > '\026'))---- stringLiteral = lexeme (- do{ str <- between (char '"')- (localTokenMode (const Any) (char '"' <?> "end of string"))- (localTokenMode (const Any) (many stringChar))- ; return (foldr (maybe id (:)) "" str)- }- <?> "literal string")-- stringChar = do{ c <- stringLetter; return (Just c) }- <|> stringEscape- <?> "string character"-- stringLetter = satisfy (\c -> (c /= '"') && (c /= '\\') && (c > '\026'))-- stringEscape = do{ char '\\'- ; do{ escapeGap ; return Nothing }- <|> do{ escapeEmpty; return Nothing }- <|> do{ esc <- escapeCode; return (Just esc) }- }-- escapeEmpty = char '&'- escapeGap = do{ many1 space- ; char '\\' <?> "end of string gap"- }---- -- escape codes- escapeCode = charEsc <|> charNum <|> charAscii <|> charControl- <?> "escape code"-- charControl = do{ char '^'- ; code <- upper- ; return (toEnum (fromEnum code - fromEnum 'A'))- }-- charNum = do{ code <- decimal- <|> do{ char 'o'; number 8 octDigit }- <|> do{ char 'x'; number 16 hexDigit }- ; return (toEnum (fromInteger code))- }-- charEsc = choice (map parseEsc escMap)- where- parseEsc (c,code) = do{ char c; return code }-- charAscii = choice (map parseAscii asciiMap)- where- parseAscii (asc,code) = try (do{ string asc; return code })--- -- escape code tables- escMap = zip ("abfnrtv\\\"\'") ("\a\b\f\n\r\t\v\\\"\'")- asciiMap = zip (ascii3codes ++ ascii2codes) (ascii3 ++ ascii2)-- ascii2codes = ["BS","HT","LF","VT","FF","CR","SO","SI","EM",- "FS","GS","RS","US","SP"]- ascii3codes = ["NUL","SOH","STX","ETX","EOT","ENQ","ACK","BEL",- "DLE","DC1","DC2","DC3","DC4","NAK","SYN","ETB",- "CAN","SUB","ESC","DEL"]-- ascii2 = ['\BS','\HT','\LF','\VT','\FF','\CR','\SO','\SI',- '\EM','\FS','\GS','\RS','\US','\SP']- ascii3 = ['\NUL','\SOH','\STX','\ETX','\EOT','\ENQ','\ACK',- '\BEL','\DLE','\DC1','\DC2','\DC3','\DC4','\NAK',- '\SYN','\ETB','\CAN','\SUB','\ESC','\DEL']--- ------------------------------------------------------------ -- Numbers- ------------------------------------------------------------ naturalOrFloat = lexeme (natFloat) <?> "number"-- float = lexeme floating <?> "float"- integer = lexeme int <?> "integer"- natural = lexeme nat <?> "natural"--- -- floats- floating = do{ n <- decimal- ; fractExponent n- }--- natFloat = do{ char '0'- ; zeroNumFloat- }- <|> decimalFloat-- zeroNumFloat = do{ n <- hexadecimal <|> octal- ; return (Left n)- }- <|> decimalFloat- <|> fractFloat 0- <|> return (Left 0)-- decimalFloat = do{ n <- decimal- ; option (Left n)- (fractFloat n)- }-- fractFloat n = do{ f <- fractExponent n- ; return (Right f)- }-- fractExponent n = do{ fract <- fraction- ; expo <- option 1.0 exponent'- ; return ((fromInteger n + fract)*expo)- }- <|>- do{ expo <- exponent'- ; return ((fromInteger n)*expo)- }-- fraction = do{ char '.'- ; digits <- many1 digit <?> "fraction"- ; return (foldr op 0.0 digits)- }- <?> "fraction"- where- op d f = (f + fromIntegral (digitToInt d))/10.0-- exponent' = do{ oneOf "eE"- ; f <- sign- ; e <- decimal <?> "exponent"- ; return (power (f e))- }- <?> "exponent"- where- power e | e < 0 = 1.0/power(-e)- | otherwise = fromInteger (10^e)--- -- integers and naturals- int = do{ f <- lexeme sign- ; n <- nat- ; return (f n)- }-- sign = (char '-' >> return negate)- <|> (char '+' >> return id)- <|> return id-- nat = zeroNumber <|> decimal-- zeroNumber = do{ char '0'- ; hexadecimal <|> octal <|> decimal <|> return 0- }- <?> ""-- decimal = number 10 digit- hexadecimal = do{ oneOf "xX"; number 16 hexDigit }- octal = do{ oneOf "oO"; number 8 octDigit }-- number base baseDigit- = do{ digits <- many1 baseDigit- ; let n = foldl (\x d -> base*x + toInteger (digitToInt d)) 0 digits- ; seq n (return n)- }-- ------------------------------------------------------------ -- Operators & reserved ops- ------------------------------------------------------------ reservedOp name =- lexeme $ try $- do{ string name- ; notFollowedBy (opLetter languageDef) <?> ("end of " ++ show name)- }-- operator =- lexeme $ try $- do{ name <- oper- ; if (isReservedOp name)- then unexpected ("reserved operator " ++ show name)- else return name- }-- oper =- do{ c <- (opStart languageDef)- ; cs <- many (opLetter languageDef)- ; return (c:cs)- }- <?> "operator"-- isReservedOp name =- isReserved (sort (reservedOpNames languageDef)) name--- ------------------------------------------------------------ -- Identifiers & Reserved words- ------------------------------------------------------------ reserved name =- lexeme $ try $- do{ caseString name- ; notFollowedBy (identLetter languageDef) <?> ("end of " ++ show name)- }-- caseString name- | caseSensitive languageDef = string name- | otherwise = do{ walk name; return name }- where- walk [] = return ()- walk (c:cs) = do{ caseChar c <?> msg; walk cs }-- caseChar c | isAlpha c = char (toLower c) <|> char (toUpper c)- | otherwise = char c-- msg = show name--- identifier =- lexeme $ try $- do{ name <- ident- ; if (isReservedName name)- then unexpected ("reserved word " ++ show name)- else return name- }--- ident- = do{ c <- identStart languageDef- ; cs <- many (identLetter languageDef)- ; return (c:cs)- }- <?> "identifier"-- isReservedName name- = isReserved theReservedNames caseName- where- caseName | caseSensitive languageDef = name- | otherwise = map toLower name--- isReserved names name- = scan names- where- scan [] = False- scan (r:rs) = case (compare r name) of- LT -> scan rs- EQ -> True- GT -> False-- theReservedNames- | caseSensitive languageDef = sort reserved- | otherwise = sort . map (map toLower) $ reserved- where- reserved = reservedNames languageDef---- ------------------------------------------------------------ -- White space & symbols- ------------------------------------------------------------ symbol name- = lexeme (string name)-- lexeme p- = do{ x <- p; whiteSpace; return x }-- whiteSpace = ignoreAbsoluteIndentation (localTokenMode (const Any) whiteSpace')- whiteSpace'- | noLine && noMulti = skipMany (simpleSpace <?> "")- | noLine = skipMany (simpleSpace <|> multiLineComment <?> "")- | noMulti = skipMany (simpleSpace <|> oneLineComment <?> "")- | otherwise = skipMany (simpleSpace <|> oneLineComment <|> multiLineComment <?> "")- where- noLine = null (commentLine languageDef)- noMulti = null (commentStart languageDef)-- simpleSpace =- skipMany1 (satisfy isSpace)-- oneLineComment =- do{ try (string (commentLine languageDef))- ; skipMany (satisfy (/= '\n'))- ; return ()- }-- multiLineComment =- do { try (string (commentStart languageDef))- ; inComment- }-- inComment- | nestedComments languageDef = inCommentMulti- | otherwise = inCommentSingle-- inCommentMulti- = do{ try (string (commentEnd languageDef)) ; return () }- <|> do{ multiLineComment ; inCommentMulti }- <|> do{ skipMany1 (noneOf startEnd) ; inCommentMulti }- <|> do{ oneOf startEnd ; inCommentMulti }- <?> "end of comment"- where- startEnd = nub (commentEnd languageDef ++ commentStart languageDef)-- inCommentSingle- = do{ try (string (commentEnd languageDef)); return () }- <|> do{ skipMany1 (noneOf startEnd) ; inCommentSingle }- <|> do{ oneOf startEnd ; inCommentSingle }- <?> "end of comment"- where- startEnd = nub (commentEnd languageDef ++ commentStart languageDef)
− Text/Parser/Indentation/Implementation.hs
@@ -1,338 +0,0 @@-module Text.Parser.Indentation.Implementation where---- Implements common code for "Indentation Senstivie Parising: Landin Revisited"------ Primary functions are:--- - TODO--- Primary driver functions are:--- - TODO---- TODO:--- Grace style indentation stream--- Haskell style indentation stream----import Control.Monad----------------------------- Indentations----------------------------- We use indent 1 for the first column. Not only is this consistent--- with how Parsec counts columns, but it also allows 'Gt' to refer to--- the first column by setting the indent to 0.---data Indentation = Indentation# Int# deriving (Eq, Ord)-type Indentation = Int-data IndentationRel = Eq | Any | Const Indentation | Ge | Gt deriving (Show, Eq)--{-# INLINE infIndentation #-}-infIndentation :: Indentation-infIndentation = maxBound--{--instance Num Indentation where--instance Show Indentation where- show i@(Indentation# i') | i' == maxBound = "Infinity"- | otherwise = show (Int# i')--}----------------------------- Indentable Stream----------------------------- We store state information about the current indentation in the--- Stream. Encoding the indentation state in the Stream is weird, but--- the other two places where we could put it don't work. The monad--- isn't rolledback when backtracking happens (which we need the--- indentation state to do), and the user state isn't available when--- we do an 'uncons'.--{-# INLINE mkIndentationState #-}-mkIndentationState :: Indentation -> Indentation -> Bool -> IndentationRel -> IndentationState-mkIndentationState lo hi mode rel- | lo == infIndentation = error "mkIndentationState: minimum indentation 'infIndentation' is out of bounds"- | lo > hi = error "mkIndentationState: minimum indentation is greater than maximum indent"- | otherwise = IndentationState lo hi mode rel---- THEOREM: indent sets are all describable by upper and lower bounds (maxBound is infinity)--- GLOBAL INVARIANT: minIndentation /= infIndentation--- GLOBAL INVARIANT: minIndentation <= maxIndentation--- GLOBAL INVARIENT: lo <= lo' where lo and lo' are minIndentation respectively before and after a monadic action--- GLOBAL INVARIENT: hi' <= hi where hi and hi' are maxIndentation respectively before and after a monadic action--data IndentationState = IndentationState {- minIndentation :: {-# UNPACK #-} !Indentation, -- inclusive, must not equal infIndentation- maxIndentation :: {-# UNPACK #-} !Indentation, -- inclusive, infIndentation (i.e., maxBound) means infinity- absMode :: !Bool, -- true if we are in 'absolute' mode- tokenRel :: !IndentationRel- } deriving (Show)- -- Our representation of maxIndentation will get us in trouble if things- -- overflow. In future we may want to use a type representing- -- Integer+Infinity However, this bug triggers *only* when there are- -- a large number of nested 'Gt' indentations which shouldn't be all- -- that common and 'local'--{-# INLINE indentationStateAbsMode #-}-indentationStateAbsMode :: IndentationState -> Bool-indentationStateAbsMode x = absMode x--{-# INLINE updateIndentation #-}--- PRIVATE: Use assertIndentation instead-updateIndentation :: IndentationState -> Indentation -> (IndentationState -> a) -> (String -> a) -> a-updateIndentation (IndentationState lo hi mode rel) i ok err = updateIndentation' lo hi (if mode then Eq else rel) i ok' err' where- ok' lo' hi' = ok (IndentationState lo' hi' False rel)- err' = err--{-# INLINE updateIndentation' #-}-updateIndentation' :: Indentation -> Indentation -> IndentationRel -> Indentation -> (Indentation -> Indentation -> a) -> (String -> a) -> a-updateIndentation' lo hi rel i ok err =- case rel of- Any -> ok lo hi- Const c | c == i -> ok lo hi- | otherwise -> err' $ "indentation "++show c- Eq | lo <= i && i <= hi -> ok i i- | otherwise -> err' $ "an indentation between "++show lo++" and "++show hi- Gt | lo < i -> ok lo (min (i-1) hi)- | otherwise -> err' $ "an indentation greater than "++show lo- Ge | lo <= i -> ok lo (min i hi)- | otherwise -> err' $ "an indentation greater than or equal to "++show lo- where err' place = err $ "Found a token at indentation "++show i++". Expecting a token at "++place++"."---- TODO: error when hi is maxIndentation---- There is no way to query the current indentation because multiple--- indentations are tried in parallel and later parsing may disqualify--- one of these indentations. However, we can assert that the current--- indentation must have a particular relation, 'r', to a given--- indentation, 'i'. The call 'assertIndent r i' does this. Calling--- 'assertIndent r i' is equivalent to consuming a pseudo-token that has--- been annotated with the relation 'r' at indentation 'i'.------ Note that the absolute indentation mode may override 'r'.-{--assertIndent :: (Monad m, Stream (IndentStream s) m t) => IndentRel -> Indent -> ParsecT (IndentStream s) u m ()-assertIndent r i = do- IndentStream lo hi mode rel s <- getInput- let ok s' = setInput (s' { absMode = mode }) -- Update input sets mode to False by default- --ok lo' hi' = setInput (IndentStream lo' hi' mode rel s)- err msg = unexpected $ "Indentation assertion '"++show r++" "++show i++"' failed. "++msg- updateIndent lo hi mode r i s ok err- --updateIndent lo hi (if mode then Eq else r) i ok err--}--{--{-# INLINE askTokenMode #-}-askTokenMode :: (Monad m) => ParsecT (IndentStream s) u m IndentRel-askTokenMode = liftM tokenRel getInput--}----------------------------- Token Modes----------------------------- Token modes determine how the current indentation must relate to--- the indentation of a token. Because several languages have special--- rules for the first token of the production, we split the token--- mode into two parts. The first part is the mode for the first--- token in a grammatical form while the second part is the mode for--- the other tokens in a grammatical form.------ Because of this split, while token modes generally follow a reader--- monad pattern, there is one important exception. Namely the--- first-token mode may follow a state monad pattern. (Thus we have--- the divergent names for the first-token and other-token query--- operators.)---- THEOREM: tokenMode == tokenMode'--- THEOREM: firstTokenMode' == firstTokenMode \/ firstTokenMode' == otherTokenMode--type LocalState a = (IndentationState -> IndentationState) -- pre- -> (IndentationState {-old-} -> IndentationState {-new-} -> IndentationState) -- post- -> a -> a--{-# INLINE localTokenMode #-}-localTokenMode :: (LocalState a)- -> (IndentationRel -> IndentationRel)- -> a -> a-localTokenMode localState f_rel = localState pre post where- pre i1 = i1 { tokenRel = f_rel (tokenRel i1) }- post i1 i2 = i2 { tokenRel = tokenRel i1 }--{-# INLINE absoluteIndentation #-}-absoluteIndentation :: LocalState a -> a -> a-absoluteIndentation localState = localState pre post where- pre i1 = i1 { absMode = True }- post i1 i2 = i2 { absMode = absMode i1 && absMode i2 }--{-# INLINE ignoreAbsoluteIndentation #-}-ignoreAbsoluteIndentation :: LocalState a -> a -> a-ignoreAbsoluteIndentation localState = localState pre post where- pre i1 = i1 { absMode = False }- post i1 i2 = i2 { absMode = absMode i1 }--{-# INLINE localAbsoluteIndentation #-}-localAbsoluteIndentation :: LocalState a -> a -> a-localAbsoluteIndentation localState = localState pre post where- pre i1 = i1 { absMode = True }- post i1 i2 = i2 { absMode = absMode i1 }----{-# INLINE askTokenMode #-}---askTokenMode :: (Monad m) => ParsecT (IndentationStream s) u m IndentationRel---askTokenMode = liftM tokenRel getInput--- TODO: assertNotAbsMod/askAbsMode--- when (absMode i2) (fail "absoluteIndentation: no tokens consumed") >>----------------------------- Local Indentations---------------------------{-# INLINE localIndentation' #-}--- PRIVATE: locally violates global invariants but used in a way that does not-localIndentation' :: LocalState a -> (Indentation -> Indentation) -> (Indentation -> Indentation) -> (Indentation -> Indentation -> Indentation) -> a -> a-localIndentation' localState f_lo f_hi f_hi' m = localState pre post m- where pre (IndentationState lo hi mode rel) = IndentationState (f_lo lo) (f_hi hi) mode rel- post (IndentationState lo hi _ _) i2 = i2 { minIndentation = lo, maxIndentation = f_hi' hi (maxIndentation i2) }--- post (IndentationStream lo hi mode rel s) i2 = IndentationStream lo (f_hi' hi (maxIndentation i2)) mode rel s---- 'localIndentation r p' specifies that the current indentation for 'p' must have relation 'r'--- relative to the current indentation of the context in which 'localIndentation r p' is called.-{-# INLINE localIndentation #-}--- NOTE: it is the responsibility of 'localState' to *not* use it's arguments if we are in absMode-localIndentation :: LocalState a -> IndentationRel -> a -> a-localIndentation _localState Eq m = m-localIndentation localState Any m = localIndentation' localState (const 0) (const infIndentation) (const) m-localIndentation localState (Const c) m- | c == infIndentation = error "localIndentation: Const indentation 'infIndentation' is out of bounds"- | otherwise = localIndentation' localState (const c) (const c) (const) m-localIndentation localState Ge m = localIndentation' localState (id) (const infIndentation) (flip const) m-localIndentation localState Gt m = localIndentation' localState (+1) (const infIndentation) (f) ({-TODO: checkOverflow >>-} m) where- f hi hi' | hi' == infIndentation || hi < hi' = hi- | hi' > 0 = hi' - 1 -- Safe only b/c hi' > 0- | otherwise = error "localIndentation: assertion failed: hi' > 0"-{-- checkOverflow = do- IndentationStream { minIndentation = lo } <- getState- when (lo == infIndentation) $ fail "localIndentation: Overflow in indentation lower bound."--}--------------------- SourcePos--{--mkSourcePosIndentStream s = SourcePosIndentStream s-newtype SourcePosIndentStream s = SourcePosIndentStream s-instance (Stream s m t) => Stream (SourcePosIndentStream s) m (Indent, t) where- uncons (SourcePosIndentStream s) = do- col <- liftM sourceColumn $ getPosition- x <- uncons s- case x of- Nothing -> return Nothing- Just x -> return (Just ((col, x), SourcePosIndentStream s))--}--------------------- Unicode char--- newtype UnicodeIndentStream--{--------------------- Based on Char-mkCharIndentStream :: s -> CharIndentStream s-mkCharIndentStream s = CharIndentStream 1 s-data CharIndentStream s = CharIndentStream { charIndentStreamColumn :: !Indent,- charIndentStreamStream :: s } deriving (Show)--instance (Stream s m Char) => Stream (CharIndentStream s) m (Indent, Char) where- uncons (CharIndentStream i s) = do- x <- uncons s- case x of- Nothing -> return Nothing- Just (c, cs) -> return (Just ((i, c), CharIndentStream (f c) cs)) where- f '\n' = 1- f '\t' = i + 8 - ((i-1) `mod` 8)- f _ = i + 1--charIndentStreamParser :: (Monad m) => ParsecT s u m t -> ParsecT (CharIndentStream s) u m (Indent, t)-charIndentStreamParser p = mkPT $ \state ->- let go (Ok a state' e) = return (Ok (sourceColumn $ statePos state, a) (state' { stateInput = CharIndentStream (sourceColumn $ statePos state') (stateInput state') }) e)- go (Error e) = return (Error e)- in runParsecT p (state { stateInput = charIndentStreamStream (stateInput state) })- >>= consumed (return . Consumed . go) (return . Empty . go)--------------------- TODO: parser based on first non-whitespace char--------------------- First token of line indents--------------------- Based on Indents---- Note that if 'p' consumes input but is at the wrong indentation, then--- 'indentStreamParser p' signals an error but does *not* consume input.--- This allows Parsec primitives like 'string' to be properly backtracked.-indentStreamParser :: (Monad m) => ParsecT s u m (Indent, t) -> ParsecT (IndentStream s) u m t-indentStreamParser p = mkPT $ \state ->- let IndentStream lo hi mode rel _ = stateInput state- go f (Ok (i, a) state' e) = updateIndent lo hi (if mode then Eq else rel) i ok err where- ok lo' hi' = return $ f $ return (Ok a (state' {stateInput = IndentStream lo' hi' False rel (stateInput state') }) e)- err msg = return $ Empty $ return $ Error (Message ("Invalid indentation. "++msg++show ((stateInput state) { tokenStream = ""})) `addErrorMessage` e)- go f (Error e) = return $ f $ return (Error e)- in runParsecT p (state { stateInput = tokenStream (stateInput state) }) >>= consumed (go Consumed) (go Empty)---- lifting operator--- token, tokens, tokenPrim, tokenPrimEx ???--- whiteSpace--- ByteString--- ByteString.Lazy--- Text--delimitedLayout :: Stream (IndentStream s) m t =>- ParsecT (IndentStream s) u m open -> Bool ->- ParsecT (IndentStream s) u m close -> Bool ->- ParsecT (IndentStream s) u m a -> ParsecT (IndentStream s) u m a-delimitedLayout open openAny close closeAny body = between open' close' (localIndent (Const 0) body) where- open' | openAny = localIndent (Const 0) open- | otherwise = open- close' | closeAny = localIndent (Const 0) close- | otherwise = close--indentedLayout :: Stream (IndentStream s) m t =>- (Maybe (ParsecT (IndentStream s) u m sep)) ->- ParsecT (IndentStream s) u m a -> ParsecT (IndentStream s) u m [a]-indentedLayout (Nothing ) clause = localIndent Gt $ many $ absoluteIndent $ clause-indentedLayout (Just sep) clause = liftM concat $ localIndent Gt $ many $ absoluteIndent $ sepBy1 clause sep--{--layout p = delimitedLayout (symbol "{") False (symbol "}") True (semiSep p)- <|> indentedLayout (Just semi) p--identifier pred = liftM fromString $ try $ identifier >>= \x -> guard (pred x) >> return x-operator pred = liftM fromString $ try $ operator >>= \x -> guard (pred x) >> return x--reserved name = (if name `elem` middleKeywords then localFirstTokenMode (const Ge) else id) $ reserved name--Numbers, Integers and Naturals are custom--dotSep-dotSep1---}--{--test :: String-test = foo where- foo = "abc \-\def" ++ ""--test2 :: Int-test2 = foo where- foo = let { x = 1;- } in x------ All code indented?- foo = 3- bar = 4--}--}
− Text/Trifecta/Indentation.hs
@@ -1,185 +0,0 @@-{-# 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
indentation.cabal view
@@ -1,8 +1,15 @@ name: indentation-version: 0.2.1.2+version: 0.3 synopsis: Indentation sensitive parsing combinators for Parsec and Trifecta description: Indentation sensitive parsing combinators for Parsec and Trifecta. . + This package provides both the Parsec and+ Trifecta combinators. It is mainly useful for+ backward compatability with older versions of+ indentation.+ Individual backends are available in the indentation-parsec and indentation-trifecta+ packages.+ . See . __Michael D. Adams and Ömer S. Ağacan__.@@ -21,63 +28,38 @@ build-type: Simple cabal-version: >=1.10 extra-source-files: CHANGELOG.md- Text/Parsec/Indentation/Examples/*.hs -homepage: https://bitbucket.org/mdmkolbe/indentation-bug-reports: https://bitbucket.org/mdmkolbe/indentation/issues+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/mdmkolbe/indentation.git+ location: https://bitbucket.org/adamsmd/indentation.git library+ hs-source-dirs: src exposed-modules: Text.Parser.Indentation.Implementation build-depends: base >=4.6 && <4.10,- mtl >=2.1+ mtl >=2.1,+ indentation-core == 0.0 if flag(Parsec)- build-depends: parsec >=3.1.5+ build-depends: parsec >=3.1.5,+ indentation-parsec == 0.0 exposed-modules: Text.Parsec.Indentation , Text.Parsec.Indentation.Char , Text.Parsec.Indentation.Token if flag(Trifecta) build-depends: trifecta >=1.4 && <1.6,- parsers >=0.10 && <0.13+ parsers >=0.10 && <0.13,+ indentation-trifecta == 0.0 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- if flag(Parsec) {- cpp-options: -DENABLE_PARSEC_TESTS- build-depends:- parsec- other-modules:- ParensParsec- }- if flag(Parsec) {- cpp-options: -DENABLE_TRIFECTA_TESTS- build-depends:- trifecta- other-modules:- ParensTrifecta- }- build-depends:- base >= 4 && < 5- , tasty >= 0.10- , tasty-hunit >= 0.9- , indentation flag Parsec description: Include indentation operators for Parsec
+ src/Text/Parsec/Indentation.hs view
@@ -0,0 +1,4 @@+{-# language PackageImports #-}+module Text.Parsec.Indentation (module Impl) where++import "indentation-parsec" Text.Parsec.Indentation as Impl
+ src/Text/Parsec/Indentation/Char.hs view
@@ -0,0 +1,4 @@+{-# language PackageImports #-}+module Text.Parsec.Indentation.Char (module Impl) where++import "indentation-parsec" Text.Parsec.Indentation.Char as Impl
+ src/Text/Parsec/Indentation/Token.hs view
@@ -0,0 +1,4 @@+{-# language PackageImports #-}+module Text.Parsec.Indentation.Token (module Impl) where++import "indentation-parsec" Text.Parsec.Indentation.Token as Impl
+ src/Text/Parser/Indentation/Implementation.hs view
@@ -0,0 +1,6 @@+{-# language PackageImports #-}++module Text.Parser.Indentation.Implementation (module Impl)+ where++import "indentation-core" Text.Parser.Indentation.Implementation as Impl
+ src/Text/Trifecta/Indentation.hs view
@@ -0,0 +1,4 @@+{-# language PackageImports #-}+module Text.Trifecta.Indentation (module Impl) where++import "indentation-trifecta" Text.Trifecta.Indentation as Impl
− tests/ParensParsec.hs
@@ -1,86 +0,0 @@-{-# LANGUAGE NoMonomorphismRestriction, FlexibleContexts #-}-module ParensParsec where--import Control.Applicative-import Text.Parsec-import Text.Parsec.Indentation-import Test.Tasty (TestTree, testGroup)-import Test.Tasty.HUnit (testCase, assertEqual, assertFailure, Assertion)- --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 = choice [ Seq <$> a' <*> a, a', return Nil ]--a' :: (Monad m, Stream s m (Char, Indentation)) => ParsecT (IndentStream s) () m A-a' = choice- [ Par <$>- between (localTokenMode (const Eq) $ char '(')- (localTokenMode (const Eq) $ char ')')- (localIndentation Gt a)- , Bra <$>- between (localTokenMode (const Ge) $ char '[')- (localTokenMode (const Ge) $ char ']')- (localIndentation Gt a)- ]---runParse input- = case runParser a () "" (mkIndentStream 0 infIndentation True Gt input) of- Left err -> Left (show err)- Right a -> Right a---- conveniences for tests-parL = Par . listToSeq-braL = Bra . listToSeq--listToSeq [] = Nil-listToSeq (x:xs) = Seq x $ listToSeq xs- -input1 = [('(', 1),- ('[', 4),- ('(', 5),- (')', 5),- (']', 7),- (')', 1)]-output1 = runParse input1-expected1 = listToSeq [ parL [braL [parL []]]- ]--input2 = [('(', 1),- ('[', 8),- ('(', 6),- (')', 6),- ('[', 8),- (']', 9),- (']', 4),- ('(', 3),- (')', 3),- (')', 1)]-output2 = runParse 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 (parsec)"- [ testCase "1" $ assertParsedOk output1 expected1- , testCase "2" $ assertParsedOk output2 expected2- ]
− tests/ParensTrifecta.hs
@@ -1,109 +0,0 @@-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
@@ -1,27 +0,0 @@-{-# LANGUAGE CPP #-}-module Main where--import Test.Tasty (defaultMain, testGroup)-#if defined(ENABLE_PARSEC_TESTS)-import qualified ParensParsec -#endif-#if defined(ENABLE_TRIFECTA_TESTS)-import qualified ParensTrifecta-#endif --#if defined(ENABLE_TRIFECTA_TESTS)-#endif--main =- defaultMain $ testGroup "All tests" $- [-#if defined(ENABLE_PARSEC_TESTS)- ParensParsec.allTests-#endif- ]- ++- [-#if defined(ENABLE_TRIFECTA_TESTS)- ParensTrifecta.allTests-#endif- ]