packages feed

LParse (empty) → 0.1.1.1

raw patch · 9 files changed

+299/−0 lines, 9 filesdep +basesetup-changed

Dependencies added: base

Files

+ LICENSE view
@@ -0,0 +1,21 @@+MIT License++Copyright (c) 2017 Marcus Völker++Permission is hereby granted, free of charge, to any person obtaining a copy+of this software and associated documentation files (the "Software"), to deal+in the Software without restriction, including without limitation the rights+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell+copies of the Software, and to permit persons to whom the Software is+furnished to do so, subject to the following conditions:++The above copyright notice and this permission notice shall be included in all+copies or substantial portions of the Software.++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+SOFTWARE.
+ LParse.cabal view
@@ -0,0 +1,30 @@+name:                LParse+version:             0.1.1.1+synopsis:            A continuation-based parser library+description:         A parser library using continuations with a possibility for failure to build parsers in a clear and concise manner.+homepage:            https://github.com/MarcusVoelker/LParse#readme+license:             MIT+license-file:        LICENSE+author:              Marcus Völker+maintainer:          marcus.voelker@rwth-aachen.de+copyright:           (c) 2017 Marcus Völker+category:            Parsing+build-type:          Simple+extra-source-files:  README.md+cabal-version:       >=1.10++library+  hs-source-dirs:      src+  exposed-modules:     Control.DoubleContinuations Text.LParse.Atomics, Text.LParse.Parser, Text.LParse.Transformers+  build-depends:       base >= 4.7 && < 5+  default-language:    Haskell2010++source-repository head+  type:     git+  location: https://github.com/MarcusVoelker/LParse++test-suite test-lparse+  type:     exitcode-stdio-1.0+  main-is:  test/Test.hs+  build-depends:  base+  default-language: Haskell2010
+ README.md view
@@ -0,0 +1,4 @@+# λParse+++![Travis-CI](https://travis-ci.org/MarcusVoelker/LParse.svg?branch=master)
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ src/Control/DoubleContinuations.hs view
@@ -0,0 +1,48 @@+{-|
+Module      : Control.DoubleContinuations 
+Description : Continuations that can succeed or fail
+Copyright   : (c) Marcus Völker, 2017
+License     : MIT
+Maintainer  : marcus.voelker@rwth-aachen.de
+
+This module describes DoubleContinuations, which are Continuations that may have succeeded or failed.
+Instead of just taking a single function (a -> r) -> r to execute after the computation has run,
+a double continuation takes two functions: one to call in case of success and one to call in case of error
+This allows for easy implementation of exception handling and structuring control flow in a pass/fail manner
+-}
+module Control.DoubleContinuations where 
+
+import Control.Applicative
+import Control.Monad
+import Data.Either
+
+-- | The double continuation. Takes two functions, one to invoke if the computation is successful, one if it errors
+data DCont r e a = DCont {run :: (a -> r) -> (e -> r) -> r}
+
+-- | Generates a continuation that always fails. For a continuation that always succeeds, see return
+throw :: e  -- ^ The error to return
+    -> DCont r e a
+throw x = DCont (\_ g -> g x)
+
+-- | Binding a Continuation means running it, then feeding the result into f to generate a new continuation, and running that
+instance Monad (DCont r e) where
+    return x = DCont (\f _ -> f x)
+    c >>= f = DCont (\btr etr -> run c (\x -> run (f x) btr etr) etr)
+
+-- | via Monad/Functor laws
+instance Functor (DCont r e) where
+    fmap = liftM
+
+-- | via Monad/Applicative laws
+instance Applicative (DCont r e) where
+    pure = return
+    f <*> a = f >>= (<$> a)
+
+-- | An empty alternative just fails with an undefined error. Branching means first trying one, and in case of failure, the other
+instance Alternative (DCont r e) where
+    empty = throw undefined
+    p1 <|> p2 = DCont (\atr etr -> run p1 atr (\_ -> run p2 atr etr))
+
+-- | Convenience function to run a computation and put the result into an Either (with Left being the error and Right being the success)
+invoke :: DCont (Either e a) e a -> (Either e a)
+invoke c = run c Right Left
+ src/Text/LParse/Atomics.hs view
@@ -0,0 +1,58 @@+{-|
+Module      : Text.LParse.Atomics
+Description : Atomic parsers for use with LParse
+Copyright   : (c) Marcus Völker, 2017
+License     : MIT
+Maintainer  : marcus.voelker@rwth-aachen.de
+
+This module implements LParse's atomic parsers, i.e., parsers that are not built up from other parsers.
+-}
+module Text.LParse.Atomics where 
+
+import Control.DoubleContinuations
+
+import Control.Applicative
+import Control.Monad
+import Data.Char
+import Text.LParse.Parser
+import Text.LParse.Transformers
+
+-- | A parser that always succeeds, parses nothing and returns unit
+noop :: Parser r t ()
+noop = return ()
+
+-- | A parser that consumes the whole input and returns it unchanged
+full :: Parser r [t] [t]
+full = many tokenReturn
+
+-- | A parser that consumes the whole input and discards it, successfully
+discard :: Parser r [t] ()
+discard = void full
+
+-- | A parser that parses nothing, but only succeeds if the input is empty
+eoi :: Parser r [t] ()
+eoi = cParse null noop ("Input not fully consumed")
+
+-- | Extracts the first token from the input and applies the given function to it
+tokenParse :: (t -> a) -> Parser r [t] a
+tokenParse f = Parser (\s -> DCont (\btr etr -> if null s then etr "Unexpected EOI" else btr (f $ head s,tail s)))
+
+-- | Consumes and returns the first token of the input
+tokenReturn :: Parser r [a] a
+tokenReturn = tokenParse id
+
+-- | Succeeds exactly if the input begins with the given sequence. On success, consumes that sequence
+consume :: (Eq t, Show t) => [t] -> Parser r [t] ()
+consume pre = cParse ((&&) <$> (all id . zipWith (==) pre) <*> ((>= length pre) . length)) (pParse (drop (length pre)) noop) ("Expected " ++ show pre)
+
+-- | Succeeds exactly if the input begins with the given token. On success, consumes that token
+consumeSingle :: (Eq t, Show t) => t -> Parser r [t] ()
+consumeSingle t = cParse (\s -> not (null s) && head s == t) (pParse tail noop) ("Expected " ++ show t)
+
+-- | Extracts the first word (i.e. contiguous string of letters) from the input and returns it
+word :: Parser r String String
+word = some (cParse (\s -> not (null s) && isLetter (head s)) tokenReturn "Expected letter")
+
+-- | Extracts the first integer (i.e. contiguous string of digits) from the input and returns it
+integer :: Parser r String Integer
+integer = read <$> some (cParse (\s -> not (null s) && isDigit (head s)) tokenReturn "Expected digit")
+ src/Text/LParse/Parser.hs view
@@ -0,0 +1,76 @@+{-|+Module      : Text.LParse.Parser+Description : Core for LParse+Copyright   : (c) Marcus Völker, 2017+License     : MIT+Maintainer  : marcus.voelker@rwth-aachen.de++This module implements LParse's core: The parser data structure, instances of the important typeclasses and functions to run the parser+-}+module Text.LParse.Parser where++import Control.DoubleContinuations++import Control.Applicative+import Control.Monad+import Control.Arrow+import qualified Control.Category as C+import Data.List++-- | The Parser structure itself wraps a function from a collection of tokens (collectively of type t) to a double continuation giving+-- back a string in case of an error (the error message) and a pair (a,t) in case of a success (the parsing result and rest of the input)+data Parser r t a = Parser {pFunc :: t -> DCont r String (a,t)}++-- | via Monad/Functor laws+instance Functor (Parser r t) where+    fmap = liftM++-- | via Monad/Applicative laws+instance Applicative (Parser r t) where+    pure = return+    f <*> a = f >>= (<$> a)++-- | an empty parser in the sense of Alternative always fails and throws nothing. Branching between parsers means trying both in a row and+-- taking the first one that succeeds+instance Alternative (Parser r t) where+    empty = Parser (const $ throw "Empty Fail")+    p1 <|> p2 = Parser ((<|>) <$> (pFunc p1) <*> (pFunc p2))++-- | returning a value means building a parser that consumes no input and just gives back the value (i.e. always succeeds)+-- the bind operator means using the parser, creating a second parser from the result (with the given function) and then parsing with that.+-- Both parsers successively consume input, i.e. @consume "a" >>= (const $ consume "b")@ will consume the string "ab"+instance Monad (Parser r t) where+    return a = Parser (\s -> return (a,s))+    a >>= f = Parser (pFunc a >=> (\(r, s') -> pFunc (f r) s'))++-- | Defined via Alternative+instance MonadPlus (Parser r t) where+    mzero = empty+    mplus = (<|>)++-- | The identity parser returns the input. Concatenating two parsers means using the parsing result of the first as tokens for the second+instance C.Category (Parser r) where+    id = Parser (\s -> return (s,s))+    (.) b a = Parser (\s -> DCont (\btr etr -> run (pFunc a s) (\(x,r) -> run (pFunc b x) (\(y,_) -> btr (y,r)) etr) etr))++-- | Lifting a function to an arrow applies the function to the input. (***) executes two parsers in parallel, giving both results as a pair +-- (but only if both succeed)+instance Arrow (Parser r) where+    arr f = Parser (\s -> return (f s, undefined))+    (***) p1 p2 = Parser (\(a,b) -> DCont (\btr etr -> run (pFunc p1 a) (\(a',ra) -> run (pFunc p2 b) (\(b',rb) -> btr ((a',b'),(ra,rb))) etr) etr))++-- | Runs the parser on the tokens, using two functions to run the contained continuation+parse :: Parser r t a -> t -> (a -> r) -> (String -> r) -> r+parse p s = run (pFunc p s) . (. fst)++-- | Same as @parse@, but giving back the results via @Either@+doParse :: Parser (Either String a) t a -> t -> Either String a+doParse p s = invoke (fst <$> pFunc p s)++-- | Runs the parser and prints the results+debugParse :: (Show a) => Parser (IO ()) t a -> t -> IO ()+debugParse p s = debugParse' p s (putStr . (\x -> show x ++ "\n"))++-- | Runs the parser and prints the results via a custom printing function+debugParse' :: Parser (IO ()) t a -> t -> (a -> IO()) ->  IO ()+debugParse' p s a = run (pFunc p s) (a . fst) (\e -> putStr ("Error: "++ e ++ "\n"))
+ src/Text/LParse/Transformers.hs view
@@ -0,0 +1,53 @@+{-|
+Module      : Text.LParse.Transformers
+Description : Parser transformers for use with LParse
+Copyright   : (c) Marcus Völker, 2017
+License     : MIT
+Maintainer  : marcus.voelker@rwth-aachen.de
+
+This module implements LParse's transformers, i.e. functions that build new parsers from other parsers
+-}
+module Text.LParse.Transformers where 
+
+import Control.DoubleContinuations
+import Text.LParse.Parser
+
+import Control.Applicative
+import Data.Char
+
+-- | Executes components in the same order as @(>>)@, but returning the first rather than the second monad. Note that @a >> b /= b << a@
+(<<) :: (Monad m) => m a -> m b -> m a
+a << b = a >>= ((b >>) . return)
+
+-- | Takes a condition the parser's input has to fulfil in order for the parser to succeed
+cParse :: (t -> Bool) -> Parser r t a -> String -> Parser r t a
+cParse c p err = Parser (\s -> if c s then pFunc p s else throw err)
+
+-- | Transforms the input before applying the parser
+pParse :: (t -> t) -> Parser r t a -> Parser r t a
+pParse f p = Parser (pFunc p . f)
+
+-- | Takes a parser that consumes separators and a parser that consumes the desired data and returns a non-empty list of desired data (separated by the separator in source)
+-- For example: @sepSome (consume " ") word@ applied to @"a banana is tasty"@ returns @["a","banana","is","tasty"]@
+sepSome :: Parser r t () -> Parser r t a -> Parser r t [a]
+sepSome sep p = ((:) <$> p <*> many (sep >> p)) <|> fmap return p
+
+-- | Same as @sepSome@, but allows empty lists
+sepMany :: Parser r t () -> Parser r t a -> Parser r t [a]
+sepMany sep p = sepSome sep p <|> return []
+
+-- | Removes all tokens from the given list from the input
+skip :: (Eq t) => [t] -> Parser r [t] a -> Parser r [t] a
+skip s = skipBy (not . (`elem` s))
+
+-- | Same as skip, but with a custom comparator
+skipBy :: (t -> Bool) -> Parser r [t] a -> Parser r [t] a
+skipBy f = pParse (filter f)
+
+-- | Skips standard whitespace characters from a String input
+skipWhitespace :: Parser r String a -> Parser r String a
+skipWhitespace = skipBy (not . isSpace)
+
+-- | Replaces the first token by applying the given function
+replace :: (t -> t) -> Parser r [t] a -> Parser r [t] a
+replace f p = Parser (pFunc p . (\(x:xs) -> f x:xs))
+ test/Test.hs view
@@ -0,0 +1,7 @@+module Main where 
+
+import System.Exit (exitSuccess)
+
+main = do
+    putStrLn "Hier entsteht eine neue Testpräsenz"
+    exitSuccess