packages feed

fractaltext-0.1.0: src/Data/FractalText/Util.hs

module Data.FractalText.Util where

import Data.FractalText.Type

import Control.Monad.Trans.Free
import Data.Functor (($>))
import qualified Data.Text as T
import qualified Data.Text.Lazy as TL
import qualified Data.Vector as V
import Lens.Micro.Platform
import Prelude hiding (break, span)
import qualified Streaming as S
import qualified Streaming.Prelude as S

nextChar :: Monad m
         => S.Stream (S.Of T.Text) m r
         -> m (Either r (Char, S.Stream (S.Of T.Text) m r))
nextChar s0 = do
  mx <- S.next s0
  case mx of
    Left r -> return $ Left r
    Right (x, s1) -> case T.uncons x of
      Nothing -> nextChar s1
      Just (c, y) -> return $ Right (c, S.yield y >> s1)

span :: Monad m => (Char -> Bool) -> S.Stream (S.Of T.Text) m r
     -> S.Stream (S.Of T.Text) m (S.Stream (S.Of T.Text) m r)
span predicate = go
 where
  go s0 = do
    ex <- S.lift $ S.next s0
    case ex of
      Left r -> return $ return r
      Right (x, s1) -> do
        let (prefix, suffix) = T.span predicate x
        if T.null suffix
          then do
            S.yield x
            go s1
          else do
            S.yield prefix
            return $ S.yield suffix >> s1

break :: Monad m => (Char -> Bool) -> S.Stream (S.Of T.Text) m r
      -> S.Stream (S.Of T.Text) m (S.Stream (S.Of T.Text) m r)
break predicate = span (not . predicate)

splitLines :: Monad m
           => S.Stream (S.Of T.Text) m r
           -> FreeT (S.Stream (S.Of T.Text) m) m r
splitLines p0 = FreeT $ go1 p0
 where
  go0 r = return $ Free $ S.yield T.empty $> FreeT (return $ Pure r)
  go1 p1 = do
    ec <- S.next p1
    case ec of
      Left r -> go0 r
      Right (txt, p2) -> if T.null txt
        then go1 p2
        else return $ Free $ go2 $ S.yield txt >> p2
  go2 p1 = do
    p2 <- break (\c -> c == '\n' || c == '\r') p1
    return $ FreeT $ do
      ec1 <- nextChar p2
      case ec1 of
        Left r -> return $ Pure r
        Right ('\n', p3) -> go1 p3
        Right ('\r', p3) -> do
          ec2 <- nextChar p3
          case ec2 of
            Left r -> go0 r
            Right ('\n', p4) -> go1 p4
            Right (c, p4) -> go1 $ S.yield (T.singleton c) >> p4
        Right _ -> error "splitLines: unreachable"

freeTToLines :: Monad m => FreeT (S.Stream (S.Of T.Text) m) m r -> m [T.Text]
freeTToLines ft = do
  step <- runFreeT ft
  case step of
    Pure _ -> return []
    Free p0 -> do
      line S.:> p1 <- S.fold (<>) T.empty id p0
      rest <- freeTToLines p1
      return $ line : rest

fromLazyText :: Monad m => TL.Text -> S.Stream (S.Of T.Text) m ()
fromLazyText = TL.foldrChunks (\e a -> S.yield e >> a) (return ())

removeAnnotation :: ItemA -> Item
removeAnnotation ItemA'EmptyList = Item'EmptyList
removeAnnotation (ItemA'List _l es) = Item'List $ flip V.map es $ \e ->
  ListElem $ e ^. listElemA'value
removeAnnotation (ItemA'Dict _l des) = Item'Dict $ flip V.map des $ \de ->
  DictElem (de ^. dictElemA'key) (removeAnnotation $ de ^. dictElemA'value)

isValidDocument :: Document -> Bool
isValidDocument = go . fst
 where
  go ItemA'EmptyList = True
  go (ItemA'List _l es) = not $ V.null es
  go (ItemA'Dict _l des) = not (V.null des)
    && V.all (go . view dictElemA'value) des