packages feed

boomerang 1.3.1 → 1.3.2

raw patch · 3 files changed

+284/−7 lines, 3 filesdep +textdep ~basedep ~mtlPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

Dependencies added: text

Dependency ranges changed: base, mtl

API changes (from Hackage documentation)

+ Text.Boomerang.Texts: (</>) :: PrinterParser TextsError [Text] b c -> PrinterParser TextsError [Text] a b -> PrinterParser TextsError [Text] a c
+ Text.Boomerang.Texts: alpha :: PrinterParser TextsError [Text] r (Char :- r)
+ Text.Boomerang.Texts: anyChar :: PrinterParser TextsError [Text] r (Char :- r)
+ Text.Boomerang.Texts: anyText :: PrinterParser TextsError [Text] r (Text :- r)
+ Text.Boomerang.Texts: char :: Char -> PrinterParser TextsError [Text] r (Char :- r)
+ Text.Boomerang.Texts: digit :: PrinterParser TextsError [Text] r (Char :- r)
+ Text.Boomerang.Texts: digits :: PrinterParser TextsError [Text] r (Text :- r)
+ Text.Boomerang.Texts: eos :: PrinterParser TextsError [Text] r r
+ Text.Boomerang.Texts: instance InitialPosition TextsError
+ Text.Boomerang.Texts: instance a ~ b => IsString (PrinterParser TextsError [Text] a b)
+ Text.Boomerang.Texts: int :: PrinterParser TextsError [Text] r (Int :- r)
+ Text.Boomerang.Texts: integer :: PrinterParser TextsError [Text] r (Integer :- r)
+ Text.Boomerang.Texts: integral :: (Integral a, Show a) => PrinterParser TextsError [Text] r (a :- r)
+ Text.Boomerang.Texts: isComplete :: [Text] -> Bool
+ Text.Boomerang.Texts: lit :: Text -> PrinterParser TextsError [Text] r r
+ Text.Boomerang.Texts: parseTexts :: PrinterParser TextsError [Text] () (r :- ()) -> [Text] -> Either TextsError r
+ Text.Boomerang.Texts: rEmpty :: PrinterParser e [Text] r (Text :- r)
+ Text.Boomerang.Texts: rText :: PrinterParser e [Text] r (Char :- r) -> PrinterParser e [Text] r (Text :- r)
+ Text.Boomerang.Texts: rText1 :: PrinterParser e [Text] r (Char :- r) -> PrinterParser e [Text] r (Text :- r)
+ Text.Boomerang.Texts: rTextCons :: PrinterParser e tok (Char :- (Text :- r)) (Text :- r)
+ Text.Boomerang.Texts: readshow :: (Read a, Show a) => PrinterParser TextsError [Text] r (a :- r)
+ Text.Boomerang.Texts: satisfy :: (Char -> Bool) -> PrinterParser TextsError [Text] r (Char :- r)
+ Text.Boomerang.Texts: satisfyStr :: (Text -> Bool) -> PrinterParser TextsError [Text] r (Text :- r)
+ Text.Boomerang.Texts: signed :: PrinterParser TextsError [Text] a (Text :- r) -> PrinterParser TextsError [Text] a (Text :- r)
+ Text.Boomerang.Texts: space :: PrinterParser TextsError [Text] r (Char :- r)
+ Text.Boomerang.Texts: type TextsError = ParserError MajorMinorPos
+ Text.Boomerang.Texts: unparseTexts :: PrinterParser e [Text] () (r :- ()) -> r -> Maybe [Text]
- Text.Boomerang.Combinators: rJust :: PrinterParser e tok (:- a_a1Hb r) (:- (Maybe a_a1Hb) r)
+ Text.Boomerang.Combinators: rJust :: PrinterParser e tok (:- a_a1Wm r) (:- (Maybe a_a1Wm) r)
- Text.Boomerang.Combinators: rLeft :: PrinterParser e tok (:- a_a4cj r) (:- (Either a_a4cj b_a4ck) r)
+ Text.Boomerang.Combinators: rLeft :: PrinterParser e tok (:- a_a4rT r) (:- (Either a_a4rT b_a4rU) r)
- Text.Boomerang.Combinators: rNothing :: PrinterParser e tok r (:- (Maybe a_a1Hb) r)
+ Text.Boomerang.Combinators: rNothing :: PrinterParser e tok r (:- (Maybe a_a1Wm) r)
- Text.Boomerang.Combinators: rRight :: PrinterParser e tok (:- b_a4ck r) (:- (Either a_a4cj b_a4ck) r)
+ Text.Boomerang.Combinators: rRight :: PrinterParser e tok (:- b_a4rU r) (:- (Either a_a4rT b_a4rU) r)

Files

Text/Boomerang/Strings.hs view
@@ -19,6 +19,7 @@ import Data.Data               (Data, Typeable) import Data.List               (stripPrefix) import Data.String             (IsString(..))+import Numeric                    (readDec, readSigned) import Text.Boomerang.Combinators (opt, rCons, rList1) import Text.Boomerang.Error       (ParserError(..),ErrorMsg(..), (<?>), condenseErrors, mkParserError) import Text.Boomerang.HStack       ((:-)(..))@@ -148,13 +149,12 @@               [(a,r)] ->                   [Right ((a, r:ps), incMinor ((length p) - (length r)) pos)] -readIntegral :: (Read a, Eq a, Num a) => String -> a+readIntegral :: (Read a, Eq a, Num a, Real a) => String -> a readIntegral s =-    case reads s of+    case (readSigned readDec) s of       [(x, [])] -> x       []  -> error "readIntegral: no parse"       _   -> error "readIntegral: ambiguous parse"-  -- | matches an 'Int' --
+ Text/Boomerang/Texts.hs view
@@ -0,0 +1,275 @@+-- | a 'PrinterParser' library for working with '[Text]'+{-# LANGUAGE DeriveDataTypeable, FlexibleContexts, FlexibleInstances, TemplateHaskell, TypeFamilies, TypeSynonymInstances, TypeOperators #-}+module Text.Boomerang.Texts+    (+    -- * Types+      TextsError+    -- * Combinators+    , (</>), alpha, anyChar, anyText, char, digit, digits, signed, eos, integral, int+    , integer, lit, readshow, satisfy, satisfyStr, space+    , rTextCons, rEmpty, rText, rText1+    -- * Running the 'PrinterParser'+    , isComplete, parseTexts, unparseTexts+    )+    where++import Prelude                    hiding ((.), id, (/))+import Control.Category           (Category((.), id))+import Data.Char                  (isAlpha, isDigit, isSpace)+import Data.String                (IsString(..))+import           Data.Text        (Text)+import qualified Data.Text        as Text+import qualified Data.Text.Read   as Text+import Text.Boomerang.Combinators (opt, duck1, manyr, somer)+import Text.Boomerang.Error       (ParserError(..),ErrorMsg(..), (<?>), condenseErrors, mkParserError)+import Text.Boomerang.HStack      ((:-)(..), arg)+import Text.Boomerang.Pos         (InitialPosition(..), MajorMinorPos(..), incMajor, incMinor)+import Text.Boomerang.Prim        (Parser(..), PrinterParser(..), parse1, xmaph, xpure, unparse1, val)++type TextsError = ParserError MajorMinorPos++instance InitialPosition TextsError where+    initialPos _ = MajorMinorPos 0 0++instance a ~ b => IsString (PrinterParser TextsError [Text] a b) where+    fromString = lit . Text.pack++-- | a constant string+lit :: Text -> PrinterParser TextsError [Text] r r+lit l = PrinterParser pf sf+    where+      pf = Parser $ \tok pos ->+           case tok of+             [] -> mkParserError pos [EOI "input", Expect (show l)]+             (p:ps)+                 | Text.null p && (not $ Text.null l) -> mkParserError pos [EOI "segment", Expect (show l)]+                 | otherwise ->+                     case Text.stripPrefix l p of+                       (Just p') ->+                           [Right ((id, p':ps), incMinor (Text.length l) pos)]+                       Nothing ->+                           mkParserError pos [UnExpect (show p), Expect (show l)]+      sf b = [ (\strings -> case strings of [] -> [l] ; (s:ss) -> ((l `Text.append` s) : ss), b)]++infixr 9 </>+-- | equivalent to @f . eos . g@+(</>) :: PrinterParser TextsError [Text] b c -> PrinterParser TextsError [Text] a b -> PrinterParser TextsError [Text] a c+f </> g = f . eos . g++-- | end of string+eos :: PrinterParser TextsError [Text] r r+eos = PrinterParser+       (Parser $ \path pos -> case path of+                   []      -> [Right ((id, []), incMajor 1 pos)]+--                   [] -> mkParserError pos [EOI "input"]+                   (p:ps)+                       | Text.null p ->+                          [ Right ((id, ps), incMajor 1 pos) ]+                       | otherwise -> mkParserError pos [Message $ "path-segment not entirely consumed: " ++ (Text.unpack p)])+       (\a -> [((Text.empty :), a)])++-- | statisfy a 'Char' predicate+satisfy :: (Char -> Bool) -> PrinterParser TextsError [Text] r (Char :- r)+satisfy p = val+  (Parser $ \tok pos ->+       case tok of+         []     -> mkParserError pos [EOI "input"]+         (s:ss) ->+             case Text.uncons s of+               Nothing -> mkParserError pos [EOI "segment"]+               (Just (c, cs))+                   | p c ->+                       [Right ((c, cs : ss), incMinor 1 pos )]+                   | otherwise ->+                       mkParserError pos [SysUnExpect $ show c]+  )+  (\c -> [ \paths -> case paths of [] -> [Text.singleton c] ; (s:ss) -> ((Text.cons c s):ss) | p c ])+++-- | satisfy a 'Text' predicate.+--+-- Note: must match the entire remainder of the 'Text' in this segment+satisfyStr :: (Text -> Bool) -> PrinterParser TextsError [Text] r (Text :- r)+satisfyStr p = val+  (Parser $ \tok pos ->+       case tok of+         []          -> mkParserError pos [EOI "input"]+         (s:ss)+             | Text.null s -> mkParserError pos [EOI "segment"]+             | p s ->+                 do [Right ((s, Text.empty:ss), incMajor 1 pos )]+             | otherwise ->+                 do mkParserError pos [SysUnExpect $ show s]+  )+  (\str -> [ \strings -> case strings of [] -> [str] ; (s:ss) -> ((str `Text.append` s):ss) | p str ])++-- | ascii digits @\'0\'..\'9\'@+digit :: PrinterParser TextsError [Text] r (Char :- r)+digit = satisfy isDigit <?> "a digit 0-9"++-- | matches alphabetic Unicode characters (lower-case, upper-case and title-case letters,+-- plus letters of caseless scripts and modifiers letters).  (Uses 'isAlpha')+alpha :: PrinterParser TextsError [Text] r (Char :- r)+alpha = satisfy isAlpha <?> "an alphabetic Unicode character"++-- | matches white-space characters in the Latin-1 range. (Uses 'isSpace')+space :: PrinterParser TextsError [Text] r (Char :- r)+space = satisfy isSpace <?> "a white-space character"++-- | any character+anyChar :: PrinterParser TextsError [Text] r (Char :- r)+anyChar = satisfy (const True)++-- | matches the specified character+char :: Char -> PrinterParser TextsError [Text] r (Char :- r)+char c = satisfy (== c) <?> show [c]++-- | lift 'Read'/'Show' to a 'PrinterParser'+--+-- There are a few restrictions here:+--+--  1. Error messages are a bit fuzzy. `Read` does not tell us where+--  or why a parse failed. So all we can do it use the the position+--  that we were at when we called read and say that it failed.+--+--  2. it is (currently) not safe to use 'readshow' on integral values+--  because the 'Read' instance for 'Int', 'Integer', etc,+readshow :: (Read a, Show a) => PrinterParser TextsError [Text] r (a :- r)+readshow =+    val readParser s+    where+      s a = [ \strings -> case strings of [] -> [Text.pack $ show a] ; (s:ss) -> (((Text.pack $ show a) `Text.append` s):ss) ]++readParser :: (Read a) => Parser TextsError [Text] a+readParser =+    Parser $ \tok pos ->+        case tok of+          []                  -> mkParserError pos [EOI "input"]+          (p:_) | Text.null p -> mkParserError pos [EOI "segment"]+          (p:ps) ->+            case reads (Text.unpack p) of+              [] -> mkParserError pos [SysUnExpect (Text.unpack p), Message $ "decoding using 'read' failed."]+              [(a,r)] ->+                  [Right ((a, (Text.pack r):ps), incMinor ((Text.length p) - (length r)) pos)]++readIntegral :: (Integral a) => Text -> a+readIntegral s =+    case (Text.signed Text.decimal) s of+      (Left e) -> error $ "readIntegral: " ++ e+      (Right (a, r))+          | Text.null r -> a+          | otherwise -> error $ "readIntegral: ambiguous parse. Left over data: " ++ Text.unpack r+++-- | the empty string+rEmpty :: PrinterParser e [Text] r (Text :- r)+rEmpty = xpure (Text.empty :-) $+              \(xs :- t) ->+                  if Text.null xs+                     then (Just t)+                     else Nothing++-- | the first character of a 'Text'+rTextCons :: PrinterParser e tok (Char :- Text :- r) (Text :- r)+rTextCons =+    xpure (arg (arg (:-)) (Text.cons)) $+          \(xs :- t) ->+              do (a, as) <- Text.uncons xs+                 return (a :- as :- t)++-- | construct/parse some 'Text' by repeatedly apply a 'Char' 0 or more times parser+rText :: PrinterParser e [Text] r (Char :- r)+      -> PrinterParser e [Text] r (Text :- r)+rText r = manyr (rTextCons . duck1 r) . rEmpty++-- | construct/parse some 'Text' by repeatedly apply a 'Char' 1 or more times parser+rText1 :: PrinterParser e [Text] r (Char :- r)+      -> PrinterParser e [Text] r (Text :- r)+rText1 r = somer (rTextCons . duck1 r) . rEmpty+++-- | a sequence of digits+digits :: PrinterParser TextsError [Text] r (Text :- r)+digits = rText digit++-- | an optional - character+--+-- Typically used with 'digits' to support signed numbers+--+-- > signed digits+signed :: PrinterParser TextsError [Text] a (Text :- r)+       -> PrinterParser TextsError [Text] a (Text :- r)+signed r = opt (rTextCons . char '-') . r++-- | matches an 'Integral' value+--+-- Note that the combinator @(rPair . integral . integral)@ is ill-defined because the parse canwell. not tell where it is supposed to split the sequence of digits to produced two ints.+integral :: (Integral a, Show a) => PrinterParser TextsError [Text] r (a :- r)+integral = xmaph readIntegral (Just . Text.pack . show)  (signed digits)++-- | matches an 'Int'+-- Note that the combinator @(rPair . int . int)@ is ill-defined because the parse canwell. not tell where it is supposed to split the sequence of digits to produced two ints.+int :: PrinterParser TextsError [Text] r (Int :- r)+int = integral++-- | matches an 'Integer'+--+-- Note that the combinator @(rPair . integer . integer)@ is ill-defined because the parse can not tell where it is supposed to split the sequence of digits to produced two ints.+integer :: PrinterParser TextsError [Text] r (Integer :- r)+integer = integral++-- | matches any 'Text'+--+-- the parser returns the remainder of the current Text segment, (but does not consume the 'end of segment'.+--+-- Note that the only combinator that should follow 'anyText' is+-- 'eos' or '</>'. Other combinators will lead to inconsistent+-- inversions.+--+-- For example, if we have:+--+-- > unparseTexts (rPair . anyText . anyText)  ("foo","bar")+--+-- That will unparse to @Just ["foobar"]@. But if we call+--+-- > parseTexts (rPair . anyText . anyText)  ["foobar"]+--+-- We will get @Right ("foobar","")@ instead of the original @Right ("foo","bar")@+anyText :: PrinterParser TextsError [Text] r (Text :- r)+anyText = val ps ss+    where+      ps = Parser $ \tok pos ->+           case tok of+             []     -> mkParserError pos [EOI "input", Expect "any string"]+--             ("":_) -> mkParserError pos [EOI "segment", Expect "any string"]+             (s:ss) -> [Right ((s, Text.empty:ss), incMinor (Text.length s) pos)]+      ss str = [\ss -> case ss of+                         []      -> [str]+                         (s:ss') -> ((str `Text.append` s) : ss')+               ]++-- | Predicate to test if we have parsed all the Texts.+-- Typically used as argument to 'parse1'+--+-- see also: 'parseTexts'+isComplete :: [Text] -> Bool+isComplete []   = True+isComplete [t]  = Text.null t+++-- | run the parser+--+-- Returns the first complete parse or a parse error.+--+-- > parseTexts (rUnit . lit "foo") ["foo"]+parseTexts :: PrinterParser TextsError [Text] () (r :- ())+             -> [Text]+             -> Either TextsError r+parseTexts pp strs =+    either (Left . condenseErrors) Right $ parse1 isComplete pp strs++-- | run the printer+--+-- > unparseTexts (rUnit . lit "foo") ()+unparseTexts :: PrinterParser e [Text] () (r :- ()) -> r -> Maybe [Text]+unparseTexts pp r = unparse1 [] pp r
boomerang.cabal view
@@ -1,5 +1,5 @@ Name:             boomerang-Version:          1.3.1+Version:          1.3.2 License:          BSD3 License-File:     LICENSE Author:           jeremy@seereason.com@@ -12,9 +12,10 @@ Build-type:       Simple  Library-        Build-Depends:    base >= 4 && < 5,-                          mtl,-                          template-haskell+        Build-Depends:    base             >= 4 && < 5,+                          mtl              >= 2.0 && <2.2,+                          template-haskell,+                          text             == 0.11.*         Exposed-Modules:  Text.Boomerang                           Text.Boomerang.Combinators                           Text.Boomerang.Error@@ -23,6 +24,7 @@                           Text.Boomerang.Prim                           Text.Boomerang.String                           Text.Boomerang.Strings+                          Text.Boomerang.Texts                           Text.Boomerang.TH          Extensions:       DeriveDataTypeable,