packages feed

parcom-lib (empty) → 0.1.0.0

raw patch · 11 files changed

+402/−0 lines, 11 filesdep +basedep +bytestringdep +containerssetup-changed

Dependencies added: base, bytestring, containers, word8

Files

+ LICENSE view
@@ -0,0 +1,30 @@+Copyright (c) 2013, Tobias Dammers++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++    * Redistributions of source code must retain the above copyright+      notice, this list of conditions and the following disclaimer.++    * 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.++    * Neither the name of Tobias Dammers nor the names of other+      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+OWNER 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
+ Text/Parcom/ByteString.hs view
@@ -0,0 +1,6 @@+module Text.Parcom.ByteString+( module Text.Parcom.ByteString.Strict+)+where++import Text.Parcom.ByteString.Strict
+ Text/Parcom/ByteString/Strict.hs view
@@ -0,0 +1,14 @@+{-#LANGUAGE MultiParamTypeClasses #-}+module Text.Parcom.ByteString.Strict+where++import Prelude hiding (head, null, tail)+import Data.ByteString+import Data.Word8+import Text.Parcom.Stream+import Text.Parcom.Word8++instance Stream ByteString Word8 where+    peek = head+    atEnd = null+    consume = tail
+ Text/Parcom/Combinators.hs view
@@ -0,0 +1,78 @@+module Text.Parcom.Combinators+( choice, namedChoice+, before, between+, many, many1, manySepBy+, times+, skip+)+where++import Text.Parcom.Core+import Text.Parcom.Internal++-- | Walk a list of options, return the first one that succeeds.+choice :: (Stream s t) => [Parcom s t a] -> Parcom s t a+choice xs = foldl (<|>) empty xs <?> "I tried to make a choice, but couldn't"++-- | Like @choice@, but each choice tagged with a human-readable name for+-- better error reporting.+namedChoice :: (Stream s t) => [(String, Parcom s t a)] -> Parcom s t a+namedChoice xs = choice (map snd xs) <?> (formatOptionList . map fst) xs++-- | Match two consecutive parser, return the first parser's result iff both+-- succeed.+before :: (Stream s t) => Parcom s t a -> Parcom s t b -> Parcom s t a+before p q = do { v <- p; q; return v }++-- | Match three consecutive parsers, return the middle parser's result iff+-- all three match. Parsers are given in the order inner, left, right.+between :: (Stream s t) => Parcom s t a -> Parcom s t l -> Parcom s t r -> Parcom s t a+between p l r = do { l; v <- p; r; return v }++-- | Match zero or more occurrences of a parser+many :: (Stream s t) => Parcom s t a -> Parcom s t [a]+many p =+    handle p f m+    where+        f e = return []+        m x = do+            xs <- many p+            return (x:xs)++-- | Match one or more occurrences of a parser+many1 :: (Stream s t) => Parcom s t a -> Parcom s t [a]+many1 p = do+    xs <- many p+    if null xs+        then fail "Expected at least one item"+        else return xs++-- | Given an item parser and a separator parser, keep parsing until the+-- separator or the item fails.+manySepBy :: (Stream s t) => Parcom s t a -> Parcom s t b -> Parcom s t [a]+manySepBy p s = go+    where+        go = do+            -- try an item+            handle p f m+            where+                -- item does not parse: return empty list (no matches)+                f e = return []+                -- item does parse: keep the item, try the separator.+                m x = handle s+                    -- separator does not parse: return the one item we have+                    (\e -> return [x])+                    -- separator does parse: recurse and prepend our item+                    (\_ -> go >>= \xs -> return (x:xs))++-- | Run the given parser n times, returning all the results as a list.+times :: (Stream s t) => Int -> Parcom s t a -> Parcom s t [a]+times 0 p = return []+times n p = do+    x <- p+    xs <- times (n - 1) p+    return (x:xs)++-- | Ignore the result of a parser.+skip :: Parcom s t a -> Parcom s t ()+skip p = p >> return ()
+ Text/Parcom/Core.hs view
@@ -0,0 +1,161 @@+{-#LANGUAGE MultiParamTypeClasses #-}+module Text.Parcom.Core+( ParcomError (..)+, SourcePosition (..)+, Parcom+, parse+, peek, next, atEnd+, try, handle+, notFollowedBy+, (<?>), (<|>), empty+, Stream, Token+)+where++import qualified Text.Parcom.Stream as Stream+import Text.Parcom.Stream (Stream, Token)+import Control.Monad (liftM, ap)+import Control.Applicative++data SourcePosition =+    SourcePosition+        { posFileName :: String+        , posLine :: Int+        , posColumn :: Int+        }+        deriving (Show)++data ParcomError =+    ParcomError+        { peErrorDescription :: String+        , peSourcePosition :: SourcePosition+        }+        deriving (Show)++data ParcomState s =+    ParcomState+        { psSourcePosition :: SourcePosition+        , psStream :: s+        }++newtype Parcom s t a = Parcom { runParcom :: ParcomState s -> (Either ParcomError a, ParcomState s) }++instance Monad (Parcom s t) where+    return x = Parcom (\s -> (Right x, s))+    fail err = Parcom (\s -> (Left $ ParcomError err (psSourcePosition s), s))+    m >>= f = Parcom $ \s ->+        let (a, s') = runParcom m s+        in case a of+            Left e -> (Left e, s')+            Right x -> runParcom (f x) s'++instance Functor (Parcom s t) where+    fmap f xs = xs >>= return . f++instance Applicative (Parcom s t) where+    pure = return+    (<*>) = ap++instance Alternative (Parcom s t) where+    (<|>) = alt+    empty = fail "empty"++runParser :: (Stream s t, Token t) => Parcom s t a -> String -> s -> (Either ParcomError a, ParcomState s)+runParser p fn str =+    runParcom p state+    where+        state =+            ParcomState+                { psSourcePosition = SourcePosition fn 1 1+                , psStream = str }++parse :: (Stream s t, Token t) => Parcom s t a -> String -> s -> Either ParcomError a+parse p fn str = fst $ runParser p fn str++getState :: Parcom s t (ParcomState s)+getState = Parcom $ \s -> (Right s, s)++useState :: (ParcomState s -> a) -> Parcom s t a+useState f = Parcom $ \s -> (Right $ f s, s)++setState :: ParcomState s -> Parcom s t ()+setState s = Parcom $ \_ -> (Right (), s)++modifyState :: (ParcomState s -> ParcomState s) -> Parcom s t ()+modifyState f = Parcom $ \s -> (Right (), f s)++handle :: Parcom s t a -> (ParcomError -> Parcom s t b) -> (a -> Parcom s t b) -> Parcom s t b+handle p f t = Parcom $ \s ->+    let (r', s') = runParcom p s+    in case r' of+        -- parse failed: run the error handler+        Left e -> runParcom (f e) s'+        -- parse succeeded: run the success handler+        Right x -> runParcom (t x) s'+++-- | Backtracking modifier; restores the parser state to the previous situation+-- if the wrapped parser fails.+try :: Parcom s t a -> Parcom s t a+try p = Parcom $ \s ->+    let (r', s') = runParcom p s+    in case r' of+        -- parse failed: return the error and restore the old state+        Left e -> (Left e, s)+        -- parse succeeded: return the result and the new state+        Right x -> (Right x, s')++-- | Return the result of the first parser that succeeds.+alt :: Parcom s t a -> Parcom s t a -> Parcom s t a+alt a b = Parcom $ \s ->+            let (r', s') = runParcom a s+            in case r' of+                Left _ -> runParcom b s+                Right x -> (Right x, s')++-- | Succeeds iff the given parser fails+notFollowedBy :: (Stream s t) => Parcom s t a -> Parcom s t ()+notFollowedBy p = Parcom $ \s ->+    let (r', s') = runParcom p s+    in case r' of+        Left _ -> (Right (), s)+        Right x -> runParcom (fail "something followed that shouldn't") s+    +-- | Gets the next token from the stream without consuming it.+-- Fails at end-of-input.+peek :: (Stream s t) => Parcom s t t+peek = do+    str <- psStream `liftM` getState+    if Stream.atEnd str+        then fail "Unexpected end of input"+        else return (Stream.peek str)++-- | Checks whether end-of-input has been reached.+atEnd :: (Stream s t) => Parcom s t Bool+atEnd = useState (Stream.atEnd . psStream)++nextLine :: SourcePosition -> SourcePosition+nextLine s =+    s { posLine = posLine s + 1, posColumn = 1 }++nextColumn :: SourcePosition -> SourcePosition+nextColumn s =+    s { posColumn = posColumn s + 1 }++-- | Gets the next token from the stream and consumes it.+-- Fails at end-of-input.+next :: (Stream s t, Token t) => Parcom s t t+next = do+    str <- psStream `liftM` getState+    if Stream.atEnd str+        then fail "Unexpected end of input"+        else do+            let (t, str') = Stream.pop str+            modifyState $ \state -> state { psStream = str' }+            if Stream.isLineDelimiter t+                then modifyState $ \s -> s { psSourcePosition = nextLine (psSourcePosition s) }+                else modifyState $ \s -> s { psSourcePosition = nextColumn (psSourcePosition s) }+            return t++(<?>) :: (Stream s t) => Parcom s t a -> String -> Parcom s t a+p <?> expected = p <|> fail ("Expected " ++ expected)
+ Text/Parcom/Internal.hs view
@@ -0,0 +1,8 @@+module Text.Parcom.Internal+where++formatOptionList :: [String] -> String+formatOptionList (x:y:[]) = x ++ " or " ++ y+formatOptionList (x:[]) = x+formatOptionList [] = ""+formatOptionList (x:xs) = x ++ ", " ++ formatOptionList xs
+ Text/Parcom/Prim.hs view
@@ -0,0 +1,42 @@+module Text.Parcom.Prim+( anyToken, oneOf, eof+, satisfy+, token, tokens+)+where++import Text.Parcom.Core+import Text.Parcom.Internal++-- | Gets the next token from the stream+anyToken :: (Stream s t, Token t) => Parcom s t t+anyToken = next++-- | Succeeds iff end-of-input has been reached+eof :: (Stream s t, Token t) => Parcom s t ()+eof = notFollowedBy anyToken <?> "end of input"++-- | Matches one token against a list of possible tokens; returns the+-- matching token.+oneOf :: (Stream s t, Token t, Show t, Eq t) => [t] -> Parcom s t t+oneOf xs = satisfy (`elem` xs) <?> (formatOptionList . map show) xs++-- | Succeeds if the given predicate is met for the next token.+satisfy :: (Stream s t, Token t) => (t -> Bool) -> Parcom s t t+satisfy p = do+    c <- peek+    if p c+        then next+        else fail "Predicate not met"++-- | Exactly match one particular token+token :: (Stream s t, Token t, Show t, Eq t) => t -> Parcom s t t+token t = satisfy (== t) <?> show t++-- | Match a series of tokens exactly+tokens :: (Stream s t, Token t, Eq t, Show t) => [t] -> Parcom s t [t]+tokens [] = return []+tokens (x:xs) = do+    c <- token x+    cs <- tokens xs+    return (c:cs)
+ Text/Parcom/Stream.hs view
@@ -0,0 +1,23 @@+{-#LANGUAGE MultiParamTypeClasses, FunctionalDependencies, FlexibleInstances #-}+module Text.Parcom.Stream+where++class Stream s t | s -> t where+    peek :: s -> t+    atEnd :: s -> Bool+    consume :: s -> s+    pop :: s -> (t, s)+    consume = snd . pop+    pop s = (peek s, consume s)++instance Stream [a] a where+    peek = head+    atEnd = null+    consume = tail++class Token t where+    isLineDelimiter :: t -> Bool++instance Token Char where+    isLineDelimiter '\n' = True+    isLineDelimiter _ = False
+ Text/Parcom/Word8.hs view
@@ -0,0 +1,10 @@+module Text.Parcom.Word8+(+)+where++import Text.Parcom.Stream+import Data.Word8++instance Token Word8 where+    isLineDelimiter = (== 13)
+ parcom-lib.cabal view
@@ -0,0 +1,28 @@+-- Initial parcom-lib.cabal generated by cabal init.  For further +-- documentation, see http://haskell.org/cabal/users-guide/++name:                parcom-lib+version:             0.1.0.0+synopsis:            A simple parser-combinator library, a bit like Parsec but without the frills+description:         Parcom provides parser combinator functionality in a string-type-agnostic way;+                     it supports strict ByteStrings (with Word8 tokens) and any list type (with+                     the element type as the token type) out-of-the-box, including plain old String.+                     Any other stream-of-tokens type can be hooked into the library; unlike Parsec,+                     none of the built-in parsers assumes char-like tokens.+homepage:            https://bitbucket.org/tdammers/parcom-lib+license:             BSD3+license-file:        LICENSE+author:              Tobias Dammers+maintainer:          tdammers@gmail.com+-- copyright:           +category:            Text+build-type:          Simple+cabal-version:       >=1.8++library+  exposed-modules: Text.Parcom.Stream, Text.Parcom.Core, Text.Parcom.Word8, Text.Parcom.ByteString, Text.Parcom.Internal, Text.Parcom.Combinators, Text.Parcom.Prim, Text.Parcom.ByteString.Strict+  -- other-modules:       +  build-depends: base ==4.5.*+               , containers ==0.4.*+               , bytestring ==0.9.*+               , word8