packages feed

LParse 0.1.3.1 → 0.2.1.0

raw patch · 6 files changed

+242/−127 lines, 6 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

+ Text.LParse.Atomics: digit :: Parser r String Integer
+ Text.LParse.Atomics: letter :: Parser r String Char
+ Text.LParse.TokenStream: class (Functor t, Foldable t) => TokenStream t
+ Text.LParse.TokenStream: cons :: TokenStream t => a -> t a -> t a
+ Text.LParse.TokenStream: instance Text.LParse.TokenStream.TokenStream GHC.Base.Maybe
+ Text.LParse.TokenStream: instance Text.LParse.TokenStream.TokenStream []
+ Text.LParse.TokenStream: nil :: TokenStream t => t a
+ Text.LParse.TokenStream: rest :: TokenStream t => t a -> t a
+ Text.LParse.TokenStream: sDrop :: (TokenStream s) => Int -> s a -> s a
+ Text.LParse.TokenStream: sFilter :: (TokenStream s) => (a -> Bool) -> s a -> s a
+ Text.LParse.TokenStream: sZip :: (TokenStream s) => s a -> s b -> s (a, b)
+ Text.LParse.TokenStream: sZipWith :: (TokenStream s) => (a -> b -> c) -> s a -> s b -> s c
+ Text.LParse.TokenStream: skipN :: (TokenStream s) => Int -> s a -> s a
+ Text.LParse.TokenStream: top :: TokenStream t => t a -> a
- Text.LParse.Atomics: consume :: (Eq t, Show t) => [t] -> Parser r [t] ()
+ Text.LParse.Atomics: consume :: (Eq t, Show (s t), TokenStream s) => (s t) -> Parser r (s t) ()
- Text.LParse.Atomics: consumeSingle :: (Eq t, Show t) => t -> Parser r [t] ()
+ Text.LParse.Atomics: consumeSingle :: (Eq t, Show t, TokenStream s) => t -> Parser r (s t) ()
- Text.LParse.Atomics: peek :: (t -> Bool) -> String -> Parser r [t] ()
+ Text.LParse.Atomics: peek :: (TokenStream s) => (t -> Bool) -> String -> Parser r (s t) ()
- Text.LParse.Atomics: tokenParse :: (t -> a) -> Parser r [t] a
+ Text.LParse.Atomics: tokenParse :: (TokenStream s) => (t -> a) -> Parser r (s t) a
- Text.LParse.Atomics: tokenReturn :: Parser r [a] a
+ Text.LParse.Atomics: tokenReturn :: (TokenStream s) => Parser r (s a) a
- Text.LParse.Transformers: replace :: (t -> t) -> Parser r [t] a -> Parser r [t] a
+ Text.LParse.Transformers: replace :: (TokenStream s) => (t -> t) -> Parser r (s t) a -> Parser r (s t) a
- Text.LParse.Transformers: skip :: (Eq t) => [t] -> Parser r [t] a -> Parser r [t] a
+ Text.LParse.Transformers: skip :: (Eq t, TokenStream s) => [t] -> Parser r (s t) a -> Parser r (s t) a
- Text.LParse.Transformers: skipBy :: (t -> Bool) -> Parser r [t] a -> Parser r [t] a
+ Text.LParse.Transformers: skipBy :: (TokenStream s) => (t -> Bool) -> Parser r (s t) a -> Parser r (s t) a

Files

CHANGELOG.md view
@@ -1,10 +1,49 @@-# Changelog
-
-## 0.1.3.0
-
-* Added `check` function
-* Improved testing facilities
-
-## 0.1.2.0
-
+# Changelog++# 0.2++Highlights:++* Switching from list-based parsing to `TokenStream`++## 0.2.1++### 0.2.1.0++* Deprecated `skipN`, replaced with `sDrop` ++## 0.2.0++### 0.2.0.0++* Added `TokenStream`, an abstraction of lists+* Used `TokenStream` to reformulate Atomics and Transformers+++# 0.1++Highlights:++* Initial Version++## 0.1.4++### 0.1.4.0++* Added `digit` and `letter` parsers++## 0.1.3++### 0.1.3.1++* Improved testing facilities++### 0.1.3.0++* Added `check` function++## 0.1.2++### 0.1.2.0+ * Added `peek` function
LParse.cabal view
@@ -1,5 +1,5 @@ name:                LParse-version:             0.1.3.1+version:             0.2.1.0 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@@ -15,7 +15,7 @@  library   hs-source-dirs:      src-  exposed-modules:     Control.DoubleContinuations Text.LParse.Atomics, Text.LParse.Parser, Text.LParse.Transformers+  exposed-modules:     Control.DoubleContinuations Text.LParse.Atomics, Text.LParse.Parser, Text.LParse.Transformers, Text.LParse.TokenStream   build-depends:       base >= 4.7 && < 5   default-language:    Haskell2010 
src/Text/LParse/Atomics.hs view
@@ -1,63 +1,71 @@-{-|
-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")
-
-
--- | Succeeds if the first token matches the given function, without consuming it
-peek :: (t -> Bool) -> String -> Parser r [t] ()
-peek c = cParse (c . head) noop+{-|+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+import Text.LParse.TokenStream++-- | 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 :: (TokenStream s) => (t -> a) -> Parser r (s t) a+tokenParse f = Parser (\s -> DCont (\btr etr -> if null s then etr "Unexpected EOI" else btr (f $ top s,rest s)))++-- | Consumes and returns the first token of the input+tokenReturn :: (TokenStream s) => Parser r (s a) a+tokenReturn = tokenParse id++-- | Succeeds exactly if the input begins with the given sequence. On success, consumes that sequence+consume :: (Eq t, Show (s t), TokenStream s) => (s t) -> Parser r (s t) ()+consume pre = cParse ((&&) <$> (all id . sZipWith (==) pre) <*> ((>= length pre) . length)) (pParse (sDrop (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, TokenStream s) => t -> Parser r (s t) ()+consumeSingle t = cParse (\s -> not (null s) && top s == t) (pParse rest noop) ("Expected " ++ show t)++-- | Extracts the first digit and returns it+digit :: Parser r String Integer+digit = read . return <$> cParse (\s -> not (null s) && isDigit (head s)) tokenReturn "Expected digit"++-- | Extracts the first digit and returns it+letter :: Parser r String Char+letter = cParse (\s -> not (null s) && isLetter (head s)) tokenReturn "Expected letter"++-- | Extracts the first word (i.e. contiguous string of letters) from the input and returns it+word :: Parser r String String+word = some letter ++-- | Extracts the first integer (i.e. contiguous string of digits) from the input and returns it+integer :: Parser r String Integer+integer = foldl (\x y -> x*10+y) 0 <$> some digit++-- | Succeeds if the first token matches the given function, without consuming it+peek :: (TokenStream s) => (t -> Bool) -> String -> Parser r (s t) ()+peek c = cParse (c . top) noop
+ src/Text/LParse/TokenStream.hs view
@@ -0,0 +1,62 @@+{-|+Module      : Text.LParse.TokenStream+Description : Underlying data structure for sequential parsing+Copyright   : (c) Marcus Völker, 2017+License     : MIT+Maintainer  : marcus.voelker@rwth-aachen.de++This module contains the `TokenStream` class, an abstraction of lists, similar to `Traversable`, but geared for use with LParse+-}+module Text.LParse.TokenStream where ++import Data.Maybe+import Data.Traversable++{-# DEPRECATED skipN "Use sDrop in place of skipN" #-}++-- | `TokenStream` abstracts a list, i.e., something that has a next element to process and a rest afterwards+class (Functor t, Foldable t) => TokenStream t where+    -- | `top` gives the next element to process. Similar to `head`+    top :: t a -> a+    -- | `rest` gives what is left after processing `top`. Similar to `tail`+    rest :: t a -> t a+    -- | `nil` gives the empty `TokenStream`. Similar to `[]`+    nil :: t a+    -- | `cons` prepends an element to the `TokenStream`. Similar to `(:)`+    cons :: a -> t a -> t a++instance TokenStream [] where+    top = head+    rest = tail+    nil = []+    cons = (:)++instance TokenStream Maybe where+    top = fromJust+    rest = const Nothing+    nil = Nothing+    cons a _ = Just a++-- | Deprecated version of `sDrop`+skipN :: (TokenStream s) => Int -> s a -> s a+skipN = sDrop ++-- | `TokenStream` version of `drop` +sDrop ::  (TokenStream s) => Int -> s a -> s a+sDrop 0 x = x+sDrop n x = rest $ sDrop (n-1) x++-- | `TokenStream` version of `zip`+sZip :: (TokenStream s) => s a -> s b -> s (a,b)+sZip = sZipWith (,)++-- | `TokenStream` version of `zipWith`+sZipWith :: (TokenStream s) => (a -> b -> c) -> s a -> s b -> s c+sZipWith f l r | null l || null r = nil+               | otherwise      = f (top l) (top r) `cons` (sZipWith f (rest l) (rest r))++-- | `TokenStream` version of `filter`+sFilter :: (TokenStream s) => (a -> Bool) -> s a -> s a+sFilter c x | null x = nil+            | c (top x) = (top x) `cons` sFilter c (rest x)+            | otherwise = sFilter c (rest x)
src/Text/LParse/Transformers.hs view
@@ -1,53 +1,54 @@-{-|
-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))+{-|+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 Text.LParse.TokenStream++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, TokenStream s) => [t] -> Parser r (s t) a -> Parser r (s t) a+skip s = skipBy (not . (`elem` s))++-- | Same as skip, but with a custom comparator+skipBy :: (TokenStream s) => (t -> Bool) -> Parser r (s t) a -> Parser r (s t) a+skipBy f = pParse (sFilter 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 :: (TokenStream s) => (t -> t) -> Parser r (s t) a -> Parser r (s t) a+replace f p = Parser (pFunc p . (\x -> f (top x) `cons` rest x))
test/Test.hs view
@@ -20,6 +20,8 @@     (consume "prefix","prefixed"),
     (consume "", "foo"),
     (consume "", ""),
+    (letter >> eoi, "b"),
+    (digit >> eoi, "4"),
     (word >> eoi, "banana")
     ]
 
@@ -28,6 +30,8 @@     (eoi,"foo"),
     (consume "prefix", "freepix"),
     (consume "prefix", ""),
+    (letter >> eoi, "banana"),
+    (digit >> eoi, "42"),
     (word >> eoi, "banana bread")
     ]
 
@@ -39,6 +43,7 @@ intCases :: [(Parser r String Integer, String, Integer)]
 intCases = [
     (integer,"123 is a nice number",123),
+    (digit,"123 is a nice number",1),
     (sum <$> sepMany (consume " ") integer,"1 4 12 61 192",1+4+12+61+192)
     ]