{-# LANGUAGE DerivingStrategies, PatternSynonyms #-}
{-|
Module      : Parsley.Internal.Backend.Machine.Types.Coins
Description : Meta-data associated with input consumption optimisations.
License     : BSD-3-Clause
Maintainer  : Jamie Willis
Stability   : unstable

This module exposes `Coins` and the relevant operations. These are used by
constant input analysis to side-step unnecessary length checks and character
reads (in the case of lookahead).

@since 1.5.0.0
-}
module Parsley.Internal.Backend.Machine.Types.Coins (
    Coins(..),
    minCoins,
    plus1, minus, canReclaim,
    pattern Zero, one, items
  ) where

import Control.Applicative (liftA2)
import Parsley.Internal.Core.CharPred (CharPred, mergePreds)

{-|
Packages together the known input that can be consumed after a length-check with the number of
characters that can be rewound on a lookahead backtrack.

@since 1.5.0.0
-}
data Coins = Coins {
    -- | The number of tokens we know must be consumed along the path to succeed.
    Coins -> Int
willConsume :: {-# UNPACK #-} !Int,
    Coins -> Int
willCache   :: {-# UNPACK #-} !Int,
    Coins -> Maybe CharPred
knownPreds  :: !(Maybe CharPred)
  } deriving stock Int -> Coins -> ShowS
[Coins] -> ShowS
Coins -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Coins] -> ShowS
$cshowList :: [Coins] -> ShowS
show :: Coins -> String
$cshow :: Coins -> String
showsPrec :: Int -> Coins -> ShowS
$cshowsPrec :: Int -> Coins -> ShowS
Show

canReclaim :: Coins -> Int
canReclaim :: Coins -> Int
canReclaim = Coins -> Int
willConsume

{-|
Makes a `Coins` value of 0.

@since 1.5.0.0
-}
pattern Zero :: Coins
pattern $bZero :: Coins
$mZero :: forall {r}. Coins -> ((# #) -> r) -> ((# #) -> r) -> r
Zero = Coins 0 0 Nothing

one :: CharPred -> Coins
one :: CharPred -> Coins
one CharPred
p = Int -> Int -> Maybe CharPred -> Coins
Coins Int
1 Int
1 (forall a. a -> Maybe a
Just CharPred
p)

items :: Int -> Coins
items :: Int -> Coins
items Int
n = Int -> Int -> Maybe CharPred -> Coins
Coins Int
n Int
0 forall a. Maybe a
Nothing

zipCoins :: (Int -> Int -> Int) -> (Int -> Int -> Int) -> (Maybe CharPred -> Maybe CharPred -> Maybe CharPred) -> Coins -> Coins -> Coins
zipCoins :: (Int -> Int -> Int)
-> (Int -> Int -> Int)
-> (Maybe CharPred -> Maybe CharPred -> Maybe CharPred)
-> Coins
-> Coins
-> Coins
zipCoins Int -> Int -> Int
f Int -> Int -> Int
g Maybe CharPred -> Maybe CharPred -> Maybe CharPred
h (Coins Int
k1 Int
c1 Maybe CharPred
cs1) (Coins Int
k2 Int
c2 Maybe CharPred
cs2) = Int -> Int -> Maybe CharPred -> Coins
Coins Int
k' Int
c' Maybe CharPred
cs'
  where
    k' :: Int
k' = Int -> Int -> Int
f Int
k1 Int
k2
    c' :: Int
c' = Int -> Int -> Int
g Int
c1 Int
c2
    cs' :: Maybe CharPred
cs' = Maybe CharPred -> Maybe CharPred -> Maybe CharPred
h Maybe CharPred
cs1 Maybe CharPred
cs2

{-|
Takes the pairwise min of two `Coins` values.

@since 1.5.0.0
-}
minCoins :: Coins -> Coins -> Coins
minCoins :: Coins -> Coins -> Coins
minCoins = (Int -> Int -> Int)
-> (Int -> Int -> Int)
-> (Maybe CharPred -> Maybe CharPred -> Maybe CharPred)
-> Coins
-> Coins
-> Coins
zipCoins forall a. Ord a => a -> a -> a
min forall a. Ord a => a -> a -> a
min (forall (f :: Type -> Type) a b c.
Applicative f =>
(a -> b -> c) -> f a -> f b -> f c
liftA2 CharPred -> CharPred -> CharPred
mergePreds)

{-|
Adds 1 to all the `Coins` values.

@since 1.5.0.0
-}
plus1 :: CharPred -> Coins -> Coins
plus1 :: CharPred -> Coins -> Coins
plus1 CharPred
p =  (Int -> Int -> Int)
-> (Int -> Int -> Int)
-> (Maybe CharPred -> Maybe CharPred -> Maybe CharPred)
-> Coins
-> Coins
-> Coins
zipCoins forall a. Num a => a -> a -> a
(+) forall a. Num a => a -> a -> a
(+) forall a b. a -> b -> a
const (CharPred -> Coins
one CharPred
p)

{-|
@since 1.5.0.0
-}
minus :: Coins -> Int -> Coins
minus :: Coins -> Int -> Coins
minus Coins
c Int
0 = Coins
c
minus (Coins Int
n Int
c Maybe CharPred
_) Int
m = Int -> Int -> Maybe CharPred -> Coins
Coins (forall a. Ord a => a -> a -> a
max (Int
n forall a. Num a => a -> a -> a
- Int
m) Int
0) (forall a. Ord a => a -> a -> a
max (Int
c forall a. Num a => a -> a -> a
- Int
m) Int
0) forall a. Maybe a
Nothing