-- |
-- Module: Staversion.Internal.Format
-- Description: formatting Result output.
-- Maintainer: Toshio Ito <debug.ito@gmail.com>
--
-- __This is an internal module. End-users should not use it.__
module Staversion.Internal.Format
       ( formatAggregatedResults,
         FormatConfig(..),
         FormatVersion,
         formatVersionCabal,
         formatVersionCabalCaret
       ) where

import Data.Foldable (fold)
import Data.Function (on)
import Data.List (intersperse)
import Data.List.NonEmpty (NonEmpty(..))
import qualified Data.List.NonEmpty as NL
import Data.Maybe (fromJust)
import Data.Monoid (mempty, mconcat, (<>))
import Data.Text (Text, pack)
import qualified Data.Text as Text
import qualified Data.Text.Lazy as TL
import Data.Text.Lazy.Builder (Builder, toLazyText, fromText, fromString)

import Staversion.Internal.Aggregate
  ( groupAllPreservingOrderBy,
    showVersionRange
  )
import Staversion.Internal.Query
  ( Query(..),
    sourceDesc,
    PackageName
  )
import Staversion.Internal.Result
  ( Result(..), ResultBody'(..), ResultSource(..), resultSourceDesc,
    AggregatedResult(..), singletonResult
  )
import Staversion.Internal.Cabal (Target(..))
import Staversion.Internal.Log (LogEntry)
import Staversion.Internal.Version (VersionRange)
import qualified Staversion.Internal.Version as V


-- | Format for 'VersionRange'.
type FormatVersion = VersionRange -> Text

-- | Let Cabal format 'VersionRange'.
formatVersionCabal :: FormatVersion
formatVersionCabal :: FormatVersion
formatVersionCabal = String -> Text
pack (String -> Text) -> (VersionRange -> String) -> FormatVersion
forall b c a. (b -> c) -> (a -> b) -> a -> c
. VersionRange -> String
showVersionRange

-- | Similar to 'formatVersionCabal', but it uses the \"caret\"
-- operator (@^>=@) where possible.
formatVersionCabalCaret :: FormatVersion
formatVersionCabalCaret :: FormatVersion
formatVersionCabalCaret = Text -> [Text] -> Text
Text.intercalate Text
" || " ([Text] -> Text) -> (VersionRange -> [Text]) -> FormatVersion
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (VersionInterval -> Text) -> [VersionInterval] -> [Text]
forall a b. (a -> b) -> [a] -> [b]
map VersionInterval -> Text
formatVersionIntervalCaret ([VersionInterval] -> [Text])
-> (VersionRange -> [VersionInterval]) -> VersionRange -> [Text]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. VersionRange -> [VersionInterval]
V.asVersionIntervals

formatVersionIntervalCaret :: V.VersionInterval -> Text
formatVersionIntervalCaret :: VersionInterval -> Text
formatVersionIntervalCaret VersionInterval
vi = case VersionInterval
vi of
  (V.LowerBound Version
lv Bound
V.InclusiveBound, V.UpperBound Version
uv Bound
V.ExclusiveBound) ->
    if Version -> Version -> Bool
isCaretOK Version
lv Version
uv
    then Text
"^>=" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Version -> Text
formatV Version
lv
    else Text
fallback
  VersionInterval
_ -> Text
fallback
  where
    formatV :: Version -> Text
formatV Version
v = String -> Text
pack (String -> Text) -> String -> Text
forall a b. (a -> b) -> a -> b
$ [String] -> String
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat ([String] -> String) -> [String] -> String
forall a b. (a -> b) -> a -> b
$ String -> [String] -> [String]
forall a. a -> [a] -> [a]
intersperse String
"." ([String] -> [String]) -> [String] -> [String]
forall a b. (a -> b) -> a -> b
$ (Int -> String) -> [Int] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map Int -> String
forall a. Show a => a -> String
show ([Int] -> [String]) -> [Int] -> [String]
forall a b. (a -> b) -> a -> b
$ Version -> [Int]
V.versionNumbers Version
v
    fallback :: Text
fallback = FormatVersion
formatVersionCabal FormatVersion -> FormatVersion
forall a b. (a -> b) -> a -> b
$ VersionIntervals -> VersionRange
V.fromVersionIntervals (VersionIntervals -> VersionRange)
-> VersionIntervals -> VersionRange
forall a b. (a -> b) -> a -> b
$ [VersionInterval] -> VersionIntervals
V.mkVersionIntervals [VersionInterval
vi]

isCaretOK :: V.Version -> V.Version -> Bool
isCaretOK :: Version -> Version -> Bool
isCaretOK Version
inc_lv Version
exc_uv = [Int] -> [Int] -> Bool
forall a. (Eq a, Num a) => [a] -> [a] -> Bool
isCaretOK' (Version -> [Int]
V.versionNumbers Version
inc_lv) (Version -> [Int]
V.versionNumbers Version
exc_uv) where
  isCaretOK' :: [a] -> [a] -> Bool
isCaretOK' [] [a]
uv'          = [a]
uv' [a] -> [a] -> Bool
forall a. Eq a => a -> a -> Bool
== [a
0,a
1]
  isCaretOK' [a
x] [a]
uv'         = [a]
uv' [a] -> [a] -> Bool
forall a. Eq a => a -> a -> Bool
== [a
x,a
1]
  isCaretOK' (a
x : a
y : [a]
_) [a]
uv' = [a]
uv' [a] -> [a] -> Bool
forall a. Eq a => a -> a -> Bool
== [a
x,a
ya -> a -> a
forall a. Num a => a -> a -> a
+a
1]



data FormatConfig = FormatConfig { FormatConfig -> FormatVersion
fconfFormatVersion :: FormatVersion
                                 }

-- | 'Left' lines and 'Right' lines are handled differently by
-- 'formatResultBlock'. It puts commas at the right places assuming
-- 'Left' lines are commented out.
type ResultLine = Either Builder Builder

data ResultBlock = RBHead Builder [ResultBlock] -- ^ header and child blocks
                 | RBLines [ResultLine] -- ^ a block, which consists of some lines.


formatAggregatedResults :: FormatConfig -> [AggregatedResult] -> TL.Text
formatAggregatedResults :: FormatConfig -> [AggregatedResult] -> Text
formatAggregatedResults FormatConfig
fconf = Builder -> Text
toLazyText (Builder -> Text)
-> ([AggregatedResult] -> Builder) -> [AggregatedResult] -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Builder] -> Builder
forall a. Monoid a => [a] -> a
mconcat ([Builder] -> Builder)
-> ([AggregatedResult] -> [Builder])
-> [AggregatedResult]
-> Builder
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (ResultBlock -> Builder) -> [ResultBlock] -> [Builder]
forall a b. (a -> b) -> [a] -> [b]
map ResultBlock -> Builder
formatResultBlock ([ResultBlock] -> [Builder])
-> ([AggregatedResult] -> [ResultBlock])
-> [AggregatedResult]
-> [Builder]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. FormatConfig -> [AggregatedResult] -> [ResultBlock]
makeSourceBlocks FormatConfig
fconf

makeSourceBlocks :: FormatConfig -> [AggregatedResult] -> [ResultBlock]
makeSourceBlocks :: FormatConfig -> [AggregatedResult] -> [ResultBlock]
makeSourceBlocks FormatConfig
fconf = (NonEmpty AggregatedResult -> ResultBlock)
-> [NonEmpty AggregatedResult] -> [ResultBlock]
forall a b. (a -> b) -> [a] -> [b]
map NonEmpty AggregatedResult -> ResultBlock
sourceBlock ([NonEmpty AggregatedResult] -> [ResultBlock])
-> ([AggregatedResult] -> [NonEmpty AggregatedResult])
-> [AggregatedResult]
-> [ResultBlock]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (AggregatedResult -> AggregatedResult -> Bool)
-> [AggregatedResult] -> [NonEmpty AggregatedResult]
forall a. (a -> a -> Bool) -> [a] -> [NonEmpty a]
groupAllPreservingOrderBy (NonEmpty ResultSource -> NonEmpty ResultSource -> Bool
forall a. Eq a => a -> a -> Bool
(==) (NonEmpty ResultSource -> NonEmpty ResultSource -> Bool)
-> (AggregatedResult -> NonEmpty ResultSource)
-> AggregatedResult
-> AggregatedResult
-> Bool
forall b c a. (b -> b -> c) -> (a -> b) -> a -> a -> c
`on` AggregatedResult -> NonEmpty ResultSource
aggResultIn) where
  sourceBlock :: NonEmpty AggregatedResult -> ResultBlock
sourceBlock results :: NonEmpty AggregatedResult
results@(AggregatedResult
head_ret :| [AggregatedResult]
_) = Builder -> [ResultBlock] -> ResultBlock
RBHead Builder
header ([ResultBlock] -> ResultBlock) -> [ResultBlock] -> ResultBlock
forall a b. (a -> b) -> a -> b
$ FormatConfig -> [AggregatedResult] -> [ResultBlock]
makeQueryBlocks FormatConfig
fconf ([AggregatedResult] -> [ResultBlock])
-> [AggregatedResult] -> [ResultBlock]
forall a b. (a -> b) -> a -> b
$ NonEmpty AggregatedResult -> [AggregatedResult]
forall a. NonEmpty a -> [a]
NL.toList NonEmpty AggregatedResult
results where
    header :: Builder
header = Builder
"------ " Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> (NonEmpty Builder -> Builder
forall (t :: * -> *) m. (Foldable t, Monoid m) => t m -> m
fold (NonEmpty Builder -> Builder) -> NonEmpty Builder -> Builder
forall a b. (a -> b) -> a -> b
$ Builder -> NonEmpty Builder -> NonEmpty Builder
forall a. a -> NonEmpty a -> NonEmpty a
NL.intersperse Builder
", " (NonEmpty Builder -> NonEmpty Builder)
-> NonEmpty Builder -> NonEmpty Builder
forall a b. (a -> b) -> a -> b
$ (ResultSource -> Builder)
-> NonEmpty ResultSource -> NonEmpty Builder
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ResultSource -> Builder
sourceHeader (NonEmpty ResultSource -> NonEmpty Builder)
-> NonEmpty ResultSource -> NonEmpty Builder
forall a b. (a -> b) -> a -> b
$ AggregatedResult -> NonEmpty ResultSource
aggResultIn AggregatedResult
head_ret)

sourceHeader :: ResultSource -> Builder
sourceHeader :: ResultSource -> Builder
sourceHeader = Text -> Builder
fromText (Text -> Builder)
-> (ResultSource -> Text) -> ResultSource -> Builder
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ResultSource -> Text
resultSourceDesc

makeQueryBlocks :: FormatConfig -> [AggregatedResult] -> [ResultBlock]
makeQueryBlocks :: FormatConfig -> [AggregatedResult] -> [ResultBlock]
makeQueryBlocks FormatConfig
fconf = ([ResultBlock] -> [ResultLine] -> [ResultBlock])
-> ([ResultBlock], [ResultLine]) -> [ResultBlock]
forall a b c. (a -> b -> c) -> (a, b) -> c
uncurry [ResultBlock] -> [ResultLine] -> [ResultBlock]
prependLines (([ResultBlock], [ResultLine]) -> [ResultBlock])
-> ([AggregatedResult] -> ([ResultBlock], [ResultLine]))
-> [AggregatedResult]
-> [ResultBlock]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (AggregatedResult
 -> ([ResultBlock], [ResultLine]) -> ([ResultBlock], [ResultLine]))
-> ([ResultBlock], [ResultLine])
-> [AggregatedResult]
-> ([ResultBlock], [ResultLine])
forall (t :: * -> *) a b.
Foldable t =>
(a -> b -> b) -> b -> t a -> b
foldr AggregatedResult
-> ([ResultBlock], [ResultLine]) -> ([ResultBlock], [ResultLine])
f ([], []) where
  prependLines :: [ResultBlock] -> [ResultLine] -> [ResultBlock]
prependLines [ResultBlock]
blocks [] = [ResultBlock]
blocks
  prependLines [ResultBlock]
blocks [ResultLine]
rlines = ([ResultLine] -> ResultBlock
RBLines [ResultLine]
rlines) ResultBlock -> [ResultBlock] -> [ResultBlock]
forall a. a -> [a] -> [a]
: [ResultBlock]
blocks
  f :: AggregatedResult
-> ([ResultBlock], [ResultLine]) -> ([ResultBlock], [ResultLine])
f AggregatedResult
ret ([ResultBlock]
blocks, [ResultLine]
rlines) = case (AggregatedResult -> Query
aggResultFor AggregatedResult
ret, AggregatedResult
-> Either String (ResultBody' (Maybe VersionRange))
aggResultBody AggregatedResult
ret) of
    (Query
_, Right (SimpleResultBody Text
name Maybe VersionRange
mver)) -> ([ResultBlock]
blocks, (FormatVersion -> Text -> Maybe VersionRange -> ResultLine
versionLine (FormatConfig -> FormatVersion
fconfFormatVersion FormatConfig
fconf) Text
name Maybe VersionRange
mver) ResultLine -> [ResultLine] -> [ResultLine]
forall a. a -> [a] -> [a]
: [ResultLine]
rlines)
    (Query
_, Right (CabalResultBody String
file Target
target [(Text, Maybe VersionRange)]
pairs)) -> (FormatConfig
-> String -> Target -> [(Text, Maybe VersionRange)] -> ResultBlock
cabalFileSuccessBlock FormatConfig
fconf String
file Target
target [(Text, Maybe VersionRange)]
pairs ResultBlock -> [ResultBlock] -> [ResultBlock]
forall a. a -> [a] -> [a]
: [ResultBlock] -> [ResultLine] -> [ResultBlock]
prependLines [ResultBlock]
blocks [ResultLine]
rlines, [])
    (Query
query, Left String
_) -> case Query -> Either ResultLine ResultBlock
makeQueryErrorReport Query
query of
      Left ResultLine
line -> ([ResultBlock]
blocks, ResultLine
line ResultLine -> [ResultLine] -> [ResultLine]
forall a. a -> [a] -> [a]
: [ResultLine]
rlines)
      Right ResultBlock
block -> (ResultBlock
block ResultBlock -> [ResultBlock] -> [ResultBlock]
forall a. a -> [a] -> [a]
: [ResultBlock] -> [ResultLine] -> [ResultBlock]
prependLines [ResultBlock]
blocks [ResultLine]
rlines, [])

versionLine :: FormatVersion -> PackageName -> Maybe VersionRange -> ResultLine
versionLine :: FormatVersion -> Text -> Maybe VersionRange -> ResultLine
versionLine FormatVersion
_ Text
name Maybe VersionRange
Nothing = Builder -> ResultLine
forall a b. a -> Either a b
Left (Builder -> ResultLine) -> Builder -> ResultLine
forall a b. (a -> b) -> a -> b
$ Builder
"-- " Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Text -> Builder
fromText Text
name Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Builder
" N/A"
versionLine FormatVersion
format_version Text
name (Just VersionRange
ver_range) = Builder -> ResultLine
forall a b. b -> Either a b
Right (Builder -> ResultLine) -> Builder -> ResultLine
forall a b. (a -> b) -> a -> b
$ Text -> Builder
fromText Text
name Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Builder
" " Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> (Text -> Builder
fromText (Text -> Builder) -> Text -> Builder
forall a b. (a -> b) -> a -> b
$ FormatVersion
format_version VersionRange
ver_range)

makeQueryErrorReport :: Query -> Either ResultLine ResultBlock
makeQueryErrorReport :: Query -> Either ResultLine ResultBlock
makeQueryErrorReport (QueryName Text
name) = ResultLine -> Either ResultLine ResultBlock
forall a b. a -> Either a b
Left (ResultLine -> Either ResultLine ResultBlock)
-> ResultLine -> Either ResultLine ResultBlock
forall a b. (a -> b) -> a -> b
$ Builder -> ResultLine
forall a b. a -> Either a b
Left (Builder -> ResultLine) -> Builder -> ResultLine
forall a b. (a -> b) -> a -> b
$ Builder
"-- " Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Text -> Builder
fromText Text
name Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Builder
" ERROR"
makeQueryErrorReport (QueryCabalFile String
file) = ResultBlock -> Either ResultLine ResultBlock
forall a b. b -> Either a b
Right (ResultBlock -> Either ResultLine ResultBlock)
-> ResultBlock -> Either ResultLine ResultBlock
forall a b. (a -> b) -> a -> b
$ String -> ResultBlock
errorReportBlock String
file
makeQueryErrorReport (QueryStackYaml String
file) = ResultBlock -> Either ResultLine ResultBlock
forall a b. b -> Either a b
Right (ResultBlock -> Either ResultLine ResultBlock)
-> ResultBlock -> Either ResultLine ResultBlock
forall a b. (a -> b) -> a -> b
$ String -> ResultBlock
errorReportBlock String
file
makeQueryErrorReport Query
QueryStackYamlDefault = ResultBlock -> Either ResultLine ResultBlock
forall a b. b -> Either a b
Right (ResultBlock -> Either ResultLine ResultBlock)
-> ResultBlock -> Either ResultLine ResultBlock
forall a b. (a -> b) -> a -> b
$ String -> ResultBlock
errorReportBlock String
"default stack.yaml"

errorReportBlock :: String -> ResultBlock
errorReportBlock :: String -> ResultBlock
errorReportBlock String
label = [ResultLine] -> ResultBlock
RBLines [Builder -> ResultLine
forall a b. a -> Either a b
Left Builder
line] where
  line :: Builder
line = Builder
"-- " Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> String -> Builder
fromString String
label Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Builder
" ERROR"

cabalFileSuccessBlock :: FormatConfig -> FilePath -> Target -> [(PackageName, Maybe VersionRange)] -> ResultBlock
cabalFileSuccessBlock :: FormatConfig
-> String -> Target -> [(Text, Maybe VersionRange)] -> ResultBlock
cabalFileSuccessBlock FormatConfig
fconf String
file Target
target [(Text, Maybe VersionRange)]
pairs = Builder -> [ResultBlock] -> ResultBlock
RBHead Builder
header [[ResultLine] -> ResultBlock
RBLines ([ResultLine] -> ResultBlock) -> [ResultLine] -> ResultBlock
forall a b. (a -> b) -> a -> b
$ ((Text, Maybe VersionRange) -> ResultLine)
-> [(Text, Maybe VersionRange)] -> [ResultLine]
forall a b. (a -> b) -> [a] -> [b]
map ((Text -> Maybe VersionRange -> ResultLine)
-> (Text, Maybe VersionRange) -> ResultLine
forall a b c. (a -> b -> c) -> (a, b) -> c
uncurry ((Text -> Maybe VersionRange -> ResultLine)
 -> (Text, Maybe VersionRange) -> ResultLine)
-> (Text -> Maybe VersionRange -> ResultLine)
-> (Text, Maybe VersionRange)
-> ResultLine
forall a b. (a -> b) -> a -> b
$ FormatVersion -> Text -> Maybe VersionRange -> ResultLine
versionLine (FormatVersion -> Text -> Maybe VersionRange -> ResultLine)
-> FormatVersion -> Text -> Maybe VersionRange -> ResultLine
forall a b. (a -> b) -> a -> b
$ FormatConfig -> FormatVersion
fconfFormatVersion FormatConfig
fconf) [(Text, Maybe VersionRange)]
pairs] where
  header :: Builder
header = Builder
"-- " Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> String -> Builder
fromString String
file Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Builder
" - " Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Builder
target_text
  target_text :: Builder
target_text = case Target
target of
    Target
TargetLibrary -> Builder
"library"
    TargetExecutable Text
n -> Builder
"executable " Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Text -> Builder
fromText Text
n
    TargetTestSuite Text
n -> Builder
"test-suite " Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Text -> Builder
fromText Text
n
    TargetBenchmark Text
n -> Builder
"benchmark " Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Text -> Builder
fromText Text
n

formatResultBlock :: ResultBlock -> Builder
formatResultBlock :: ResultBlock -> Builder
formatResultBlock (RBHead Builder
header [ResultBlock]
blocks) = Builder
header Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Builder
"\n" Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> [Builder] -> Builder
forall a. Monoid a => [a] -> a
mconcat ((ResultBlock -> Builder) -> [ResultBlock] -> [Builder]
forall a b. (a -> b) -> [a] -> [b]
map ResultBlock -> Builder
formatResultBlock [ResultBlock]
blocks)
formatResultBlock (RBLines [ResultLine]
rlines) = ([Builder] -> Builder
forall a. Monoid a => [a] -> a
mconcat ([Builder] -> Builder) -> [Builder] -> Builder
forall a b. (a -> b) -> a -> b
$ (ResultLine -> Builder) -> [ResultLine] -> [Builder]
forall a b. (a -> b) -> [a] -> [b]
map ((Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Builder
"\n") (Builder -> Builder)
-> (ResultLine -> Builder) -> ResultLine -> Builder
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Builder -> Builder)
-> (Builder -> Builder) -> ResultLine -> Builder
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either Builder -> Builder
forall a. a -> a
id Builder -> Builder
forall a. a -> a
id) ([ResultLine] -> [Builder]) -> [ResultLine] -> [Builder]
forall a b. (a -> b) -> a -> b
$ [ResultLine] -> [ResultLine]
tailCommas [ResultLine]
rlines) Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Builder
"\n" where
  tailCommas :: [ResultLine] -> [ResultLine]
tailCommas = ([ResultLine], Bool) -> [ResultLine]
forall a b. (a, b) -> a
fst (([ResultLine], Bool) -> [ResultLine])
-> ([ResultLine] -> ([ResultLine], Bool))
-> [ResultLine]
-> [ResultLine]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (ResultLine -> ([ResultLine], Bool) -> ([ResultLine], Bool))
-> ([ResultLine], Bool) -> [ResultLine] -> ([ResultLine], Bool)
forall (t :: * -> *) a b.
Foldable t =>
(a -> b -> b) -> b -> t a -> b
foldr ResultLine -> ([ResultLine], Bool) -> ([ResultLine], Bool)
forall a b.
(Semigroup a, Semigroup b, IsString a, IsString b) =>
Either a b -> ([Either a b], Bool) -> ([Either a b], Bool)
f ([], Bool
False)
               -- flag: True if it has already encountered the last Right element in the list.
  f :: Either a b -> ([Either a b], Bool) -> ([Either a b], Bool)
f Either a b
eb ([Either a b]
ret, Bool
flag) = let (Either a b
next_e, Bool
next_flag) = [Either a b] -> Bool -> Either a b -> (Either a b, Bool)
forall a b a.
(Semigroup a, Semigroup b, IsString a, IsString b) =>
[a] -> Bool -> Either a b -> (Either a b, Bool)
getNext [Either a b]
ret Bool
flag Either a b
eb
                     in (Either a b
next_eEither a b -> [Either a b] -> [Either a b]
forall a. a -> [a] -> [a]
:[Either a b]
ret, Bool
next_flag)
  getNext :: [a] -> Bool -> Either a b -> (Either a b, Bool)
getNext [] Bool
flag e :: Either a b
e@(Left a
_) = (Either a b
e, Bool
flag)
  getNext [a]
_ Bool
flag (Left a
b) = (a -> Either a b
forall a b. a -> Either a b
Left (a
b a -> a -> a
forall a. Semigroup a => a -> a -> a
<> a
","), Bool
flag)
  getNext [a]
_ Bool
False e :: Either a b
e@(Right b
_) = (Either a b
e, Bool
True)
  getNext [a]
_ Bool
True (Right b
b) = (b -> Either a b
forall a b. b -> Either a b
Right (b
b b -> b -> b
forall a. Semigroup a => a -> a -> a
<> b
","), Bool
True)