packages feed

PageIO 0.0.1 → 0.0.2

raw patch · 7 files changed

+212/−98 lines, 7 filesPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

API changes (from Hackage documentation)

- Text.PageIO.Transform: doResult :: Sheet -> LabelMap [OrderBy Label] -> SheetResult -> ([PageCapacity], FitAttempt) -> ([PageCapacity], FitAttempt)
- Text.PageIO.Transform: type Doc = [Page]
+ Text.PageIO.Extract: instance Monoid SheetResult
+ Text.PageIO.LabelMap: intersection :: LabelMap a -> LabelMap b -> LabelMap a
+ Text.PageIO.LabelMap: union :: LabelMap a -> LabelMap a -> LabelMap a
+ Text.PageIO.LabelMap: unionWith :: (a -> a -> a) -> LabelMap a -> LabelMap a -> LabelMap a
+ Text.PageIO.Parser: bareLabel :: Parser Label
+ Text.PageIO.Transform: MkDoc :: !SheetResult -> !ByteString -> Doc
+ Text.PageIO.Transform: MkDocBinding :: !SheetResult -> !Page -> !PageBinding -> DocBinding
+ Text.PageIO.Transform: bindDoc :: Sheet -> [Page] -> [SheetResult] -> [DocBinding]
+ Text.PageIO.Transform: data Doc
+ Text.PageIO.Transform: data DocBinding
+ Text.PageIO.Transform: doAttempt :: LabelMap [OrderBy Label] -> SheetResult -> FitAttempt -> FitAttempt
+ Text.PageIO.Transform: doCapacity :: Sheet -> SheetResult -> [PageCapacity] -> [PageCapacity]
+ Text.PageIO.Transform: docBinding :: DocBinding -> !PageBinding
+ Text.PageIO.Transform: docContent :: Doc -> !ByteString
+ Text.PageIO.Transform: docMeta :: Doc -> !SheetResult
+ Text.PageIO.Transform: docPage :: DocBinding -> !Page
+ Text.PageIO.Transform: docResult :: DocBinding -> !SheetResult
+ Text.PageIO.Transform: emitDoc :: [(SheetResult, Page)] -> Doc
+ Text.PageIO.Transform: instance Eq Doc
+ Text.PageIO.Transform: instance Eq DocBinding
+ Text.PageIO.Transform: instance Ord Doc
+ Text.PageIO.Transform: instance Ord DocBinding
+ Text.PageIO.Transform: instance Show Doc
+ Text.PageIO.Transform: instance Show DocBinding
+ Text.PageIO.Transform: packPages :: [Page] -> ByteString
+ Text.PageIO.Transform: parsePages :: Sheet -> [Page] -> [Doc]
+ Text.PageIO.Types: VLabel :: !Label -> Variable
+ Text.PageIO.Types: sheetName :: Sheet -> !Label
+ Text.PageIO.Types: valToInt :: Value -> Int
+ Text.PageIO.Types: valToIntVal :: Value -> Value
- Text.PageIO.Extract: MkSheetResult :: LabelMap Value -> LabelMap BlockResult -> SheetResult
+ Text.PageIO.Extract: MkSheetResult :: !LabelMap Value -> !LabelMap BlockResult -> SheetResult
- Text.PageIO.Extract: resultBlocks :: SheetResult -> LabelMap BlockResult
+ Text.PageIO.Extract: resultBlocks :: SheetResult -> !LabelMap BlockResult
- Text.PageIO.Extract: resultFields :: SheetResult -> LabelMap Value
+ Text.PageIO.Extract: resultFields :: SheetResult -> !LabelMap Value
- Text.PageIO.Parser: readSheet :: String -> IO (Either ParseError Sheet)
+ Text.PageIO.Parser: readSheet :: FilePath -> IO Sheet
- Text.PageIO.Transform: MkAppliedVariable :: Row -> Col -> Value -> AppliedVariable
+ Text.PageIO.Transform: MkAppliedVariable :: !Row -> !Col -> !Value -> AppliedVariable
- Text.PageIO.Transform: MkBlockData :: Row -> [Ordered Area] -> BlockData
+ Text.PageIO.Transform: MkBlockData :: !Row -> ![Ordered Area] -> BlockData
- Text.PageIO.Transform: MkSlot :: Row -> [Label] -> Slot
+ Text.PageIO.Transform: MkSlot :: !Row -> ![Label] -> Slot
- Text.PageIO.Transform: avCol :: AppliedVariable -> Col
+ Text.PageIO.Transform: avCol :: AppliedVariable -> !Col
- Text.PageIO.Transform: avRow :: AppliedVariable -> Row
+ Text.PageIO.Transform: avRow :: AppliedVariable -> !Row
- Text.PageIO.Transform: avValue :: AppliedVariable -> Value
+ Text.PageIO.Transform: avValue :: AppliedVariable -> !Value
- Text.PageIO.Transform: dataAreas :: BlockData -> [Ordered Area]
+ Text.PageIO.Transform: dataAreas :: BlockData -> ![Ordered Area]
- Text.PageIO.Transform: dataSize :: BlockData -> Row
+ Text.PageIO.Transform: dataSize :: BlockData -> !Row
- Text.PageIO.Transform: fillVariables :: Sheet -> Doc -> Doc
+ Text.PageIO.Transform: fillVariables :: Sheet -> [SheetResult] -> [Page] -> [Page]
- Text.PageIO.Transform: makeDoc :: Sheet -> [(SheetResult, Page)] -> Doc
+ Text.PageIO.Transform: makeDoc :: Sheet -> [DocBinding] -> Doc
- Text.PageIO.Transform: slotBlocks :: Slot -> [Label]
+ Text.PageIO.Transform: slotBlocks :: Slot -> ![Label]
- Text.PageIO.Transform: slotSize :: Slot -> Row
+ Text.PageIO.Transform: slotSize :: Slot -> !Row
- Text.PageIO.Transform: transformPages :: Sheet -> [Page] -> [Doc]
+ Text.PageIO.Transform: transformPages :: Sheet -> [Page] -> Sheet -> [Page] -> [Doc]
- Text.PageIO.Types: DAscending :: a -> OrderBy a
+ Text.PageIO.Types: DAscending :: !a -> OrderBy a
- Text.PageIO.Types: DDescending :: a -> OrderBy a
+ Text.PageIO.Types: DDescending :: !a -> OrderBy a
- Text.PageIO.Types: MkBlock :: Row -> LabelMap Pattern -> LabelMap Field -> [OrderBy Label] -> [Filter] -> Block
+ Text.PageIO.Types: MkBlock :: !Row -> !LabelMap Pattern -> !LabelMap Field -> ![OrderBy Label] -> ![Filter] -> Block
- Text.PageIO.Types: MkBox :: Col -> Row -> Col -> Row -> Box
+ Text.PageIO.Types: MkBox :: !Col -> !Row -> Col -> !Row -> Box
- Text.PageIO.Types: MkField :: Box -> Maybe Variable -> Bool -> FieldFormat -> Field
+ Text.PageIO.Types: MkField :: !Box -> !Maybe Variable -> !Bool -> !FieldFormat -> Field
- Text.PageIO.Types: MkFilter :: Label -> Operator -> Match -> Filter
+ Text.PageIO.Types: MkFilter :: !Label -> !Operator -> !Match -> Filter
- Text.PageIO.Types: MkFrame :: Box -> LabelMap Block -> Frame
+ Text.PageIO.Types: MkFrame :: !Box -> !LabelMap Block -> Frame
- Text.PageIO.Types: MkPattern :: Box -> Match -> Bool -> Pattern
+ Text.PageIO.Types: MkPattern :: !Box -> !Match -> !Bool -> Pattern
- Text.PageIO.Types: MkSheet :: Box -> LabelMap Pattern -> LabelMap Field -> [Frame] -> [Label] -> Sheet
+ Text.PageIO.Types: MkSheet :: !Label -> !Box -> !LabelMap Pattern -> !LabelMap Field -> ![Frame] -> ![Label] -> Sheet
- Text.PageIO.Types: ONot :: Operator -> Operator
+ Text.PageIO.Types: ONot :: !Operator -> Operator
- Text.PageIO.Types: VCount :: Scope -> Label -> Variable
+ Text.PageIO.Types: VCount :: !Scope -> !Label -> Variable
- Text.PageIO.Types: VLiteral :: Value -> Variable
+ Text.PageIO.Types: VLiteral :: !Value -> Variable
- Text.PageIO.Types: VSum :: Scope -> Label -> Variable
+ Text.PageIO.Types: VSum :: !Scope -> !Label -> Variable
- Text.PageIO.Types: blockFields :: Block -> LabelMap Field
+ Text.PageIO.Types: blockFields :: Block -> !LabelMap Field
- Text.PageIO.Types: blockFilterBy :: Block -> [Filter]
+ Text.PageIO.Types: blockFilterBy :: Block -> ![Filter]
- Text.PageIO.Types: blockLines :: Block -> Row
+ Text.PageIO.Types: blockLines :: Block -> !Row
- Text.PageIO.Types: blockOrderBy :: Block -> [OrderBy Label]
+ Text.PageIO.Types: blockOrderBy :: Block -> ![OrderBy Label]
- Text.PageIO.Types: blockPatterns :: Block -> LabelMap Pattern
+ Text.PageIO.Types: blockPatterns :: Block -> !LabelMap Pattern
- Text.PageIO.Types: boxBottom :: Box -> Row
+ Text.PageIO.Types: boxBottom :: Box -> !Row
- Text.PageIO.Types: boxLeft :: Box -> Col
+ Text.PageIO.Types: boxLeft :: Box -> !Col
- Text.PageIO.Types: boxTop :: Box -> Row
+ Text.PageIO.Types: boxTop :: Box -> !Row
- Text.PageIO.Types: fieldBox :: Field -> Box
+ Text.PageIO.Types: fieldBox :: Field -> !Box
- Text.PageIO.Types: fieldFormat :: Field -> FieldFormat
+ Text.PageIO.Types: fieldFormat :: Field -> !FieldFormat
- Text.PageIO.Types: fieldKeepSpaces :: Field -> Bool
+ Text.PageIO.Types: fieldKeepSpaces :: Field -> !Bool
- Text.PageIO.Types: fieldVariable :: Field -> Maybe Variable
+ Text.PageIO.Types: fieldVariable :: Field -> !Maybe Variable
- Text.PageIO.Types: filterField :: Filter -> Label
+ Text.PageIO.Types: filterField :: Filter -> !Label
- Text.PageIO.Types: filterMatch :: Filter -> Match
+ Text.PageIO.Types: filterMatch :: Filter -> !Match
- Text.PageIO.Types: filterOperator :: Filter -> Operator
+ Text.PageIO.Types: filterOperator :: Filter -> !Operator
- Text.PageIO.Types: frameBlocks :: Frame -> LabelMap Block
+ Text.PageIO.Types: frameBlocks :: Frame -> !LabelMap Block
- Text.PageIO.Types: frameBox :: Frame -> Box
+ Text.PageIO.Types: frameBox :: Frame -> !Box
- Text.PageIO.Types: patternBox :: Pattern -> Box
+ Text.PageIO.Types: patternBox :: Pattern -> !Box
- Text.PageIO.Types: patternMatch :: Pattern -> Match
+ Text.PageIO.Types: patternMatch :: Pattern -> !Match
- Text.PageIO.Types: patternUseWildcards :: Pattern -> Bool
+ Text.PageIO.Types: patternUseWildcards :: Pattern -> !Bool
- Text.PageIO.Types: sheetBox :: Sheet -> Box
+ Text.PageIO.Types: sheetBox :: Sheet -> !Box
- Text.PageIO.Types: sheetFields :: Sheet -> LabelMap Field
+ Text.PageIO.Types: sheetFields :: Sheet -> !LabelMap Field
- Text.PageIO.Types: sheetFrames :: Sheet -> [Frame]
+ Text.PageIO.Types: sheetFrames :: Sheet -> ![Frame]
- Text.PageIO.Types: sheetGroupBy :: Sheet -> [Label]
+ Text.PageIO.Types: sheetGroupBy :: Sheet -> ![Label]
- Text.PageIO.Types: sheetPatterns :: Sheet -> LabelMap Pattern
+ Text.PageIO.Types: sheetPatterns :: Sheet -> !LabelMap Pattern
- Text.PageIO.Types: vLabel :: Variable -> Label
+ Text.PageIO.Types: vLabel :: Variable -> !Label
- Text.PageIO.Types: vScope :: Variable -> Scope
+ Text.PageIO.Types: vScope :: Variable -> !Scope
- Text.PageIO.Types: vValue :: Variable -> Value
+ Text.PageIO.Types: vValue :: Variable -> !Value

Files

PageIO.cabal view
@@ -1,5 +1,5 @@ name:               PageIO-version:            0.0.1+version:            0.0.2 copyright:          2008 Audrey Tang license:            BSD3 license-file:       LICENSE@@ -21,3 +21,4 @@ extra-source-files: README hs-source-dirs:     src category:           Text+ghc-options:        -O2
src/Text/PageIO/Extract.hs view
@@ -1,5 +1,5 @@ {-# LANGUAGE GeneralizedNewtypeDeriving, RecordPuns #-}-{-# OPTIONS -fno-warn-name-shadowing #-}+{-# OPTIONS -fno-warn-name-shadowing -funbox-strict-fields #-}  module Text.PageIO.Extract where import Data.Maybe@@ -13,11 +13,18 @@     deriving (Eq, Ord, Monoid)  data SheetResult = MkSheetResult-    { resultFields  :: LabelMap Value-    , resultBlocks  :: LabelMap BlockResult+    { resultFields  :: !(LabelMap Value)+    , resultBlocks  :: !(LabelMap BlockResult)     }     deriving (Eq, Ord) +instance Monoid SheetResult where+    mempty = MkSheetResult mempty mempty+    mappend (MkSheetResult xf xb) (MkSheetResult yf yb) +        = MkSheetResult (LM.union xf yf) (LM.unionWith mappend xb yb)+    mconcat xs+        = MkSheetResult (LM.unions (map resultFields xs)) (LM.unionsWith mappend (map resultBlocks xs))+ instance Show BlockResult where     show (MkBlockResult []) = "[]"     show (MkBlockResult rs) = concatMap prettyBlockResult rs@@ -69,7 +76,11 @@     val = pageVal $ crop patternBox page  extractField :: Page -> Field -> Value-extractField page MkField{ fieldBox } = pageVal $ crop fieldBox page+extractField page MkField{ fieldBox, fieldFormat } = case fieldFormat of+    FNumeric{}  -> valToIntVal val+    _           -> val+    where+    val = pageVal $ crop fieldBox page  extractBlocks :: LabelMap Block -> Page -> [(Label, BlockResult)] extractBlocks blocks page@(MkPage lns) = case blockResults of
src/Text/PageIO/LabelMap.hs view
@@ -42,6 +42,12 @@ elems :: LabelMap a -> [a] elems = IM.elems . labelMap +union :: LabelMap a -> LabelMap a -> LabelMap a+union (MkLabelMap x) (MkLabelMap y) = MkLabelMap (IM.union x y)++unionWith :: (a -> a -> a) -> LabelMap a -> LabelMap a -> LabelMap a+unionWith f (MkLabelMap x) (MkLabelMap y) = MkLabelMap (IM.unionWith f x y)+ unions :: [LabelMap a] -> LabelMap a unions = MkLabelMap . IM.unions . Prelude.map labelMap @@ -72,3 +78,5 @@ mapMaybeWithKey :: (Label -> a -> Maybe b) -> LabelMap a -> LabelMap b mapMaybeWithKey f = MkLabelMap . IM.mapMaybeWithKey (f . keyToLabel) . labelMap +intersection :: LabelMap a -> LabelMap b -> LabelMap a+intersection (MkLabelMap x) (MkLabelMap y) = MkLabelMap (IM.intersection x y)
src/Text/PageIO/Parser.hs view
@@ -2,6 +2,7 @@  import Text.Parsec import Text.Parsec.ByteString+import Data.Char (isDigit) import Data.ByteString.Lazy.Char8 (pack, ByteString, toChunks) import Text.PageIO.Types import Control.Monad (liftM3, liftM4)@@ -10,8 +11,12 @@ import qualified Data.ByteString.Char8 as S import qualified Text.PageIO.LabelMap as LM -readSheet :: String -> IO (Either ParseError Sheet)-readSheet = parseFromFile sheet+readSheet :: FilePath -> IO Sheet+readSheet fn = do+    rv <- parseFromFile sheet fn+    case rv of+        Right s     -> return s+        Left err    -> fail $ show err  parseMaybe :: Parser a -> Parser (Maybe a) parseMaybe r = fmap Just r <|> return Nothing@@ -20,7 +25,8 @@ maybeFieldVariable = parseMaybe $ do     char '$'     choice-        [ sym "PAGE" >> return VPage+        [ char '$'   >> fmap VLabel bareLabel+        , sym "PAGE" >> return VPage         , literalVariable         , functionVariable         ]@@ -41,10 +47,15 @@         , sym "doc."    >> return SDoc         , return SPage         ]-    fld <- many1 $ noneOf ".) "+    fld <- bareLabel     sym ")"-    return $ fun scope (toLabel fld)+    return $ fun scope fld +bareLabel :: Parser Label+bareLabel = do+    s   <- many1 $ noneOf ".;) "+    ret $ toLabel s+ maybeFieldFormat :: Parser (Maybe FieldFormat) maybeFieldFormat = parseMaybe $ do      sym "Format"@@ -104,6 +115,8 @@  sheet :: Parser Sheet sheet = do+    sym "Event"+    name    <- labelStr     manyTill anyChar (sym "UseCharPos" <|> sym "UseGridPos")     sym "Sheet"     right   <- num@@ -115,7 +128,8 @@     frames  <- many frame     sym "End"     ret $ MkSheet-        { sheetBox      = MkBox+        { sheetName     = name+        , sheetBox      = MkBox             { boxLeft   = 1             , boxTop    = 1             , boxRight  = right
src/Text/PageIO/Run.hs view
@@ -39,7 +39,8 @@     case S.split '\x0C' content of         []      -> return []         (hd:tl) -> do-            let pages = map (MkPage . map dropCR . S.lines) (hd:map (S.tail . S.dropWhile (/= '\n')) tl)+            let pages = map (MkPage . map dropCR . S.lines)+                      $ filter ((>0) . S.length) (hd:map (S.tail . S.dropWhile (/= '\n')) tl)             length (pageLines $ last pages) `seq` unsafeFinalize content             return pages     where
src/Text/PageIO/Transform.hs view
@@ -1,40 +1,44 @@ {-# LANGUAGE RecordPuns, ParallelListComp, PatternGuards #-}-{-# OPTIONS -fno-warn-name-shadowing #-}+{-# OPTIONS -fno-warn-name-shadowing -funbox-strict-fields #-}  module Text.PageIO.Transform where import Data.Maybe import Data.Monoid-import Data.Char (isDigit) import Data.Function (on)-import Data.List (find, inits, tails, sortBy, groupBy)+import Data.List (find, inits, tails, sortBy, groupBy, intersperse) import Text.Printf import qualified Text.PageIO.LabelMap as LM import qualified Data.ByteString.Char8 as S+import qualified Data.ByteString.Lazy.Char8 as L  import Text.PageIO.Types import Text.PageIO.Extract (extractPage, SheetResult(..), BlockResult(..), Area) -type Doc = [Page]+data Doc = MkDoc+    { docMeta    :: !SheetResult+    , docContent :: !L.ByteString+    }+    deriving (Show, Eq, Ord)  type ValueMap = LabelMap [Value] data AppliedVariable = MkAppliedVariable-    { avRow     :: Row-    , avCol     :: Col-    , avValue   :: Value+    { avRow     :: !Row+    , avCol     :: !Col+    , avValue   :: !Value     }     deriving (Show, Eq, Ord)  data Slot = MkSlot-    { slotSize      :: Row-    , slotBlocks    :: [Label]+    { slotSize      :: !Row+    , slotBlocks    :: ![Label]     }     deriving (Eq, Ord, Show)  type Ordered a = ([OrderBy (Maybe Value)], a)  data BlockData = MkBlockData-    { dataSize      :: Row-    , dataAreas     :: [Ordered Area]+    { dataSize      :: !Row+    , dataAreas     :: ![Ordered Area]     }     deriving (Eq, Ord, Show) @@ -53,21 +57,59 @@ -- The actual data bound to that area. type PageBinding = LabelMap [Area] --- Turn a list of page into pages grouped by results-transformPages :: Sheet -> [Page] -> [Doc]-transformPages sheet pages = map (makeDoc sheet) docGroups+parsePages :: Sheet -> [Page] -> [Doc]+parsePages sheetIn pagesIn = map emitDoc docGroupsOut     where-    docGroups = case sheetGroupBy sheet of-        []      -> [resultAndPages]-        lbls    -> groupBy ((==) `on` docKeys) resultAndPages+    docGroupsOut = case sheetGroupBy sheetIn of+        []      -> [resultsIn]+        lbls    -> groupBy ((==) `on` docKeys) resultsIn             where             docKeys (res, _) = map (`LM.lookup` resultFields res) lbls-    resultAndPages = -        [ (res, page)-        | Just res  <- map (extractPage sheet) pages-        | page      <- pages-        ]+    resultsIn = [ (res, page) | (Just res, page) <- map (\p -> (extractPage sheetIn p, p)) pagesIn ] +emitDoc :: [(SheetResult, Page)] -> Doc+emitDoc xs = MkDoc meta (packPages pages)+    where+    meta = mconcat results+    results = map fst xs+    pages   = map snd xs+++-- Turn a list of page into pages grouped by results+transformPages :: Sheet -> [Page] -> Sheet -> [Page] -> [Doc]+transformPages sheetIn pagesIn sheetOut pagesOut = map (makeDoc sheetOut) docGroupsOut+    where+    bindingsOut = concatMap (bindDoc sheetOut pagesOut) docGroupsIn+    docGroupsOut = case sheetGroupBy sheetOut of+        []      -> [bindingsOut]+        lbls    -> groupBy ((==) `on` docKeys) bindingsOut+            where+            docKeys MkDocBinding{ docResult } = map (`LM.lookup` resultFields docResult) lbls+    docGroupsIn = case sheetGroupBy sheetIn of+        []      -> [resultsIn]+        lbls    -> groupBy ((==) `on` docKeys) resultsIn+            where+            docKeys res = map (`LM.lookup` resultFields res) lbls+    resultsIn = [ res | Just res <- map (extractPage sheetIn) pagesIn ]++makeDoc :: Sheet -> [DocBinding] -> Doc+makeDoc sheetOut xs = MkDoc meta . packPages $ fillVariables sheetOut results+    [ makePage sheetOut b p+    | b <- map docBinding xs+    | p <- map docPage xs+    ]+    where+    meta = mconcat results+    results = map docResult xs++packPages :: [Page] -> L.ByteString+packPages ps = unpages [ L.unlines [ L.fromChunks [l] | l <- pageLines p ] | p <- ps ]+    where+    unpages :: [L.ByteString] -> L.ByteString+    unpages [] = L.empty+    unpages ss = (L.concat $ intersperse nl ss) `L.append` nl -- half as much space+        where nl = L.pack "\x0C\n"+ -- Using Sheet+Page as template to rewrite a page -- First, rewrite SheetResult to eliminate all Variable fields -- Next, populate all fields@@ -81,27 +123,40 @@ -- -- XXX - If data would expand, then maybe repeat the first page indefinitely? ---makeDoc :: Sheet -> [(SheetResult, Page)] -> Doc-makeDoc sheet resultAndPages = case find (isJust . fst) pageBindings of-    Just (Just bindings, boundPages) -> fillVariables sheet-        [ makePage sheet b p+data DocBinding = MkDocBinding+    { docResult     :: !SheetResult+    , docPage       :: !Page+    , docBinding    :: !PageBinding+    }+    deriving (Show, Eq, Ord)++bindDoc :: Sheet -> [Page] -> [SheetResult] -> [DocBinding]+bindDoc sheetOut pagesOut resultsIn = case find (\(x, _, _) -> isJust x) pageBindings of+    Just (Just bindings, boundPages, boundResults) -> +        [ MkDocBinding r p b+        | r <- boundResults         | b <- bindings         | p <- boundPages         ]-    _  -> error "Impossible - cannot bind?"+    _  -> []     where-    results             = map fst resultAndPages-    pages               = map snd resultAndPages-    orders              = sheetBlockOrderBys sheet-    (capacity, attempt) = foldr (doResult sheet orders) ([], mempty) results +    resultsOut          = map (maybe (error "Roundtrip failed!") id . extractPage sheetOut) pagesOut+    orders              = sheetBlockOrderBys sheetOut+    capacity            = foldr (doCapacity sheetOut) [] resultsOut +    attempt             = foldr (doAttempt orders) mempty resultsIn     capacityTails       = repeatTails capacity-    pageTails           = repeatTails pages+    pageTails           = repeatTails pagesOut+    resultTails         = repeatTails resultsIn     pageBindings        = -        [ (tryFit pc sortedAttempt, pages)-        | pc    <- capacityTails-        | pages <- pageTails+        [ (tryFit pc sortedAttempt, pages', results')+        | pc        <- capacityTails+        | pages'    <- pageTails+        | results'  <- resultTails         ]-    sortedAttempt       = fmap (\dat -> dat{ dataAreas = sortBy (compare `on` fst) $ dataAreas dat }) attempt+    sortedAttempt       = (`fmap` filteredAttempt) $ \dat ->+        dat{ dataAreas = sortBy (compare `on` fst) $ dataAreas dat }+    filteredAttempt     = attempt `LM.intersection` capacityLabels+    capacityLabels      = LM.fromList [ (k, ()) | k <- concatMap (concatMap slotBlocks) capacity ]  -- Given "abc", generate ["", "c", "bc", "abc", "aabc", "aaabc", "aaaabc"...] repeatTails :: [a] -> [[a]]@@ -111,17 +166,21 @@     infinitePrefixes = inits (repeat x)  -- We now calculate the applied vars for each page-fillVariables :: Sheet -> Doc -> Doc-fillVariables sheet pages =+fillVariables :: Sheet -> [SheetResult] -> [Page] -> [Page]+fillVariables sheet results pages =     [ fillPageVariables appliedVars p     | p             <- pages     | appliedVars   <- map applyVariable ([1..] `zip` valueMaps)     ]     where     vars        = sheetVariableFields sheet-    valueMaps   = map makeValueMap results+    valueMaps   = map makeValueMap+        [ MkSheetResult rf nr+        | MkSheetResult rf _  <- results+        | MkSheetResult _ nr <- newResults+        ]     docVals     = LM.unionsWith (++) valueMaps-    results     = map (maybe (error "Roundtrip failed!") id . extractPage sheet) pages+    newResults  = map (maybe (error "1Roundtrip failed!") id . extractPage sheet) pages     applyVariable :: (Int, ValueMap) -> LabelMap AppliedVariable     applyVariable (pageNum, pageVals) = LM.mapMaybeWithKey applyOneVariable vars         where@@ -143,9 +202,13 @@                     SDoc    -> docVals                     SPage   -> pageVals             getVar VPage                = formatNumber pageNum-            getVar (VSum scope label)   = formatDotted $ sum (map parseVal $ valOf scope label)+            getVar (VSum scope label)   = formatDotted $ sum (map valToInt $ valOf scope label)             getVar (VCount scope label) = formatNumber $ length (valOf scope label)-            getVar (VLiteral lit)       = lit `S.append` S.replicate (len - S.length lit) ' '+            getVar (VLiteral lit)       = formatLiteral lit+            getVar (VLabel label)       = formatLiteral $ case valOf SPage label of+                []      -> S.empty+                (x:_)   -> x+            formatLiteral lit = lit `S.append` S.replicate (len - S.length lit) ' '             formatNumber = S.pack . printf ("%" ++ show len ++ "d")             formatDotted n = S.pack $ (replicate pad ' ') ++ dottedStr ++ ".00"                 where@@ -154,10 +217,6 @@                 dottedStr   = reverse (addDot $ reverse str)                 addDot (x:y:z:rest@(_:_))   = (x:y:z:',':addDot rest)                 addDot xs                   = xs-            parseVal :: Value -> Int-            parseVal val = case S.readInt (S.filter isDigit (S.takeWhile (/= '.') val)) of-                Just (num, _)   -> num-                _               -> 0  makeValueMap :: SheetResult -> ValueMap makeValueMap MkSheetResult{ resultFields, resultBlocks } = LM.unionsWith (++) (fieldMap:blockMaps)@@ -220,20 +279,27 @@     where     origLinePadded         | padLength <= 0    = origLine-        | otherwise         = origLine `S.append` S.replicate padLength ' ' -    padLength       = S.length origLine - (col + areaLength - 1)+        | otherwise         = origLine `S.append` S.replicate padLength '-' +    padLength       = (col + areaLength - 1) - S.length origLine     (before, rest)  = S.splitAt (col-1) origLinePadded     after           = S.drop areaLength rest     areaLength      = S.length areaLine -doResult :: Sheet -> LabelMap [OrderBy Label] -> SheetResult -> ([PageCapacity], FitAttempt)-            -> ([PageCapacity], FitAttempt)-doResult MkSheet{ sheetFrames } orders MkSheetResult{ resultBlocks } (pcs, att) = (pc:pcs, att')+doCapacity :: Sheet -> SheetResult -> [PageCapacity] -> [PageCapacity]+doCapacity MkSheet{ sheetFrames } MkSheetResult{ resultBlocks } pcs = pc:pcs     where     pc              = map frameToSlot framesOccured     framesOccured   = filter (labelOccured . frameBlocks) sheetFrames     labelOccured lm = any (`LM.member` lm) resultLabels     resultLabels    = LM.keys resultBlocks+    frameToSlot MkFrame{ frameBox, frameBlocks } = MkSlot+        { slotSize   = boxBottom frameBox - boxTop frameBox + 1+        , slotBlocks = LM.keys frameBlocks+        }++doAttempt :: LabelMap [OrderBy Label] -> SheetResult -> FitAttempt -> FitAttempt+doAttempt orders MkSheetResult{ resultBlocks } att = att'+    where     att'            = LM.unionsWith mappend [att, LM.mapMaybeWithKey blockToData resultBlocks]     blockToData lbl (MkBlockResult lms) = case areas of          []              -> Nothing@@ -246,10 +312,6 @@             Just orderBys   -> \vals -> map (fmap (`LM.lookup` vals)) orderBys             Nothing         -> const []         areas = [ (orderFrom vals, area) | (area, vals) <- lms ]-    frameToSlot MkFrame{ frameBox, frameBlocks } = MkSlot-        { slotSize   = boxBottom frameBox - boxTop frameBox + 1-        , slotBlocks = LM.keys frameBlocks-        }  areaRows :: Area -> Row areaRows (MkPage lns) = length lns@@ -267,7 +329,10 @@ sheetVariableFields MkSheet{ sheetFrames, sheetFields } = LM.unions filteredMaps     where     filteredMaps = map (LM.filter (isJust . fieldVariable)) fieldMaps-    fieldMaps = sheetFields : concatMap frameVariableFields sheetFrames+    fieldMaps = LM.mapWithKey addVariable sheetFields : concatMap frameVariableFields sheetFrames+    addVariable lbl fld@MkField{ fieldVariable } = case fieldVariable of+        Just{}  -> fld+        _       -> fld{ fieldVariable = Just (VLabel lbl) }     frameVariableFields frame@MkFrame{ frameBox } = map blockVariableFields blocks         where         blocks    = LM.elems (frameBlocks frame)
src/Text/PageIO/Types.hs view
@@ -1,8 +1,11 @@+{-# OPTIONS -funbox-strict-fields #-} module Text.PageIO.Types (module Text.PageIO.Types, module Text.PageIO.LabelMap) where import Text.PageIO.LabelMap (LabelMap, Label, toLabel, fromLabel) import Data.ByteString.Internal (inlinePerformIO, memcmp, ByteString(..))+import Data.Char (isDigit) import Foreign.Ptr import Foreign.ForeignPtr+import qualified Data.ByteString.Char8 as S  newtype Page = MkPage { pageLines :: [Value] }     deriving (Show, Eq, Ord)@@ -17,28 +20,29 @@ type Value       = ByteString  data Box = MkBox-    { boxLeft   :: Col-    , boxTop    :: Row+    { boxLeft   :: !Col+    , boxTop    :: !Row     , boxRight  :: Col-    , boxBottom :: Row+    , boxBottom :: !Row     }     deriving (Show, Eq, Ord)  data Sheet = MkSheet-    { sheetBox      :: Box-    , sheetPatterns :: LabelMap Pattern-    , sheetFields   :: LabelMap Field-    , sheetFrames   :: [Frame]-    , sheetGroupBy  :: [Label]+    { sheetName     :: !Label+    , sheetBox      :: !Box+    , sheetPatterns :: !(LabelMap Pattern)+    , sheetFields   :: !(LabelMap Field)+    , sheetFrames   :: ![Frame]+    , sheetGroupBy  :: ![Label] --  , sheetPositioning          :: CharPos | GridPos --  , sheetUseBlockSortPriority :: Bool     }     deriving (Show, Eq, Ord)  data Pattern = MkPattern-    { patternBox            :: Box-    , patternMatch          :: Match-    , patternUseWildcards   :: Bool+    { patternBox            :: !Box+    , patternMatch          :: !Match+    , patternUseWildcards   :: !Bool     }     deriving (Show, Eq, Ord) @@ -47,36 +51,37 @@  data Variable     = VPage-    | VSum{ vScope :: Scope, vLabel :: Label }-    | VCount{ vScope :: Scope, vLabel :: Label }-    | VLiteral{ vValue :: Value }+    | VSum{ vScope :: !Scope, vLabel :: !Label }+    | VCount{ vScope :: !Scope, vLabel :: !Label }+    | VLabel{ vLabel :: !Label }+    | VLiteral{ vValue :: !Value }     deriving (Show, Eq, Ord)  data Field = MkField-    { fieldBox              :: Box-    , fieldVariable         :: Maybe Variable-    , fieldKeepSpaces       :: Bool-    , fieldFormat           :: FieldFormat+    { fieldBox              :: !Box+    , fieldVariable         :: !(Maybe Variable)+    , fieldKeepSpaces       :: !Bool+    , fieldFormat           :: !FieldFormat     }     deriving (Show, Eq, Ord)  data Frame = MkFrame-    { frameBox              :: Box-    , frameBlocks           :: LabelMap Block+    { frameBox              :: !Box+    , frameBlocks           :: !(LabelMap Block)     }     deriving (Show, Eq, Ord) -data Operator = ONot Operator | OContains | OEq | OEndsWith | OStartsWith+data Operator = ONot !Operator | OContains | OEq | OEndsWith | OStartsWith     deriving (Show, Eq, Ord)  data Filter = MkFilter-    { filterField       :: Label-    , filterOperator    :: Operator-    , filterMatch       :: Match+    { filterField       :: !Label+    , filterOperator    :: !Operator+    , filterMatch       :: !Match     }     deriving (Show, Eq, Ord) -data OrderBy a = DAscending a | DDescending a+data OrderBy a = DAscending !a | DDescending !a     deriving (Show, Eq)  instance Functor OrderBy where@@ -90,11 +95,11 @@     compare _               _               = GT  data Block = MkBlock-    { blockLines            :: Row-    , blockPatterns         :: LabelMap Pattern-    , blockFields           :: LabelMap Field-    , blockOrderBy          :: [OrderBy Label]-    , blockFilterBy         :: [Filter]+    { blockLines            :: !Row+    , blockPatterns         :: !(LabelMap Pattern)+    , blockFields           :: !(LabelMap Field)+    , blockOrderBy          :: ![OrderBy Label]+    , blockFilterBy         :: ![Filter] --  , blockRule             :: Rule --  , blockSortPriority     :: Priority     }@@ -118,3 +123,12 @@                         rv <- memcmp matchPtr (valuePtr `plusPtr` n) sz                         if rv == 0 then return True else go (n+1)                  in go 0++valToIntVal :: Value -> Value+valToIntVal = S.filter isDigit . S.takeWhile (/= '.')++valToInt :: Value -> Int+valToInt val = case S.readInt (valToIntVal val) of+    Just (num, _)   -> num+    _               -> 0+