{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE OverloadedStrings #-}

-- | The strict building blocks of the code generator: packed text, strict
-- pairs, and the few operations on them that "Unison.Util.Text" and
-- "Unison.Util.Deque" don't have.
--
-- The generator's state and everything it produces are made of these, of
-- 'Deque' (a finger tree with no laziness anywhere) and of strict record
-- fields, so that forcing the state to weak head normal form forces all of
-- it: no thunk over the text of a module outlives the step that made it,
-- and the text is packed from the start (a 'Text' is a rope of packed
-- chunks, so appending to a long one doesn't copy it).
module Unison.Runtime.JIT.Strict
  ( Text,
    Pair (..),
    Triple (..),
    tshow,
    unlinesT,
    intercalateT,
    iforM_,
  )
where

import Control.Monad (foldM_)
import Unison.Util.Deque (Deque)
import Unison.Util.Text (Text)
import Unison.Util.Text qualified as UT

data Pair a b = Pair !a !b

data Triple a b c = Triple !a !b !c

tshow :: (Show a) => a -> Text
tshow :: forall a. Show a => a -> Text
tshow = String -> Text
UT.pack (String -> Text) -> (a -> String) -> a -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> String
forall a. Show a => a -> String
show

-- | Every element followed by a newline.
unlinesT :: Deque Text -> Text
unlinesT :: Deque Text -> Text
unlinesT = (Text -> Text -> Text) -> Text -> Deque Text -> Text
forall b a. (b -> a -> b) -> b -> Deque a -> b
forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
foldl' (\Text
acc Text
l -> Text
acc Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
l Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"\n") Text
forall a. Monoid a => a
mempty

-- | The elements with the separator between each two.
intercalateT :: Text -> Deque Text -> Text
intercalateT :: Text -> Deque Text -> Text
intercalateT Text
sep Deque Text
xs = case (Pair Bool Text -> Text -> Pair Bool Text)
-> Pair Bool Text -> Deque Text -> Pair Bool Text
forall b a. (b -> a -> b) -> b -> Deque a -> b
forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
foldl' Pair Bool Text -> Text -> Pair Bool Text
step (Bool -> Text -> Pair Bool Text
forall a b. a -> b -> Pair a b
Pair Bool
False Text
forall a. Monoid a => a
mempty) Deque Text
xs of Pair Bool
_ Text
t -> Text
t
  where
    step :: Pair Bool Text -> Text -> Pair Bool Text
step (Pair Bool
False Text
_) Text
x = Bool -> Text -> Pair Bool Text
forall a b. a -> b -> Pair a b
Pair Bool
True Text
x
    step (Pair Bool
True Text
acc) Text
x = Bool -> Text -> Pair Bool Text
forall a b. a -> b -> Pair a b
Pair Bool
True (Text
acc Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
sep Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
x)

-- | 'forM_' with the element's position.
iforM_ :: (Monad m) => Deque a -> (Int -> a -> m ()) -> m ()
iforM_ :: forall (m :: * -> *) a.
Monad m =>
Deque a -> (Int -> a -> m ()) -> m ()
iforM_ Deque a
xs Int -> a -> m ()
f = (Int -> a -> m Int) -> Int -> Deque a -> m ()
forall (t :: * -> *) (m :: * -> *) b a.
(Foldable t, Monad m) =>
(b -> a -> m b) -> b -> t a -> m ()
foldM_ (\ !Int
i a
x -> Int -> a -> m ()
f Int
i a
x m () -> m Int -> m Int
forall a b. m a -> m b -> m b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> Int -> m Int
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Int
i Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1)) Int
0 Deque a
xs