{-# LANGUAGE DerivingStrategies #-}
{-|
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(..),
    int, zero,
    minCoins, maxCoins,
    plus1, plus, minus,
    plusNotReclaim,
  ) where

{-|
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 :: Int,
    -- | The number of tokens we can reclaim if the parser backtracks.
    Coins -> Int
canReclaim :: Int
  } deriving stock Int -> Coins -> ShowS
[Coins] -> ShowS
Coins -> String
(Int -> Coins -> ShowS)
-> (Coins -> String) -> ([Coins] -> ShowS) -> Show Coins
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

{-|
Makes a `Coins` value with equal quantities of coins and characters.

@since 1.5.0.0
-}
int :: Int -> Coins
int :: Int -> Coins
int Int
n = Int -> Int -> Coins
Coins Int
n Int
n

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

@since 1.5.0.0
-}
zero :: Coins
zero :: Coins
zero = Int -> Coins
int Int
0

zipCoins :: (Int -> Int -> Int) -> Coins -> Coins -> Coins
zipCoins :: (Int -> Int -> Int) -> Coins -> Coins -> Coins
zipCoins Int -> Int -> Int
f (Coins Int
k1 Int
r1) (Coins Int
k2 Int
r2) = Int -> Int -> Coins
Coins (Int -> Int -> Int
f Int
k1 Int
k2) (Int -> Int -> Int
f Int
r1 Int
r2)

{-|
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) -> Coins -> Coins -> Coins
zipCoins Int -> Int -> Int
forall a. Ord a => a -> a -> a
min

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

@since 1.5.0.0
-}
maxCoins :: Coins -> Coins -> Coins
maxCoins :: Coins -> Coins -> Coins
maxCoins = (Int -> Int -> Int) -> Coins -> Coins -> Coins
zipCoins Int -> Int -> Int
forall a. Ord a => a -> a -> a
max

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

@since 1.5.0.0
-}
plus1 :: Coins -> Coins
plus1 :: Coins -> Coins
plus1 = Coins -> Coins -> Coins
plus (Int -> Int -> Coins
Coins Int
1 Int
1)

{-|
Performs the pairwise addition of two `Coins` values.

@since 1.5.0.0
-}
plus :: Coins -> Coins -> Coins
plus :: Coins -> Coins -> Coins
plus = (Int -> Int -> Int) -> Coins -> Coins -> Coins
zipCoins Int -> Int -> Int
forall a. Num a => a -> a -> a
(+)

{-|
Performs the pairwise subtraction of two `Coins` values.

@since 1.5.0.0
-}
minus :: Coins -> Coins -> Coins
minus :: Coins -> Coins -> Coins
minus = (Int -> Int -> Int) -> Coins -> Coins -> Coins
zipCoins (-)

{-|
A verson of plus where the reclaim value remains constant.

@since 1.5.0.0
-}
plusNotReclaim :: Coins -> Int -> Coins
plusNotReclaim :: Coins -> Int -> Coins
plusNotReclaim (Coins Int
k Int
r) Int
n = Int -> Int -> Coins
Coins (Int
k Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
n) Int
r