-- editorconfig-checker-disable-file
{-# LANGUAGE FlexibleContexts #-}
-- | Functions for computing variable usage inside terms.
module UntypedPlutusCore.Analysis.Usages (termUsages, Usages, getUsageCount, allUsed) where

import UntypedPlutusCore.Core.Type
import UntypedPlutusCore.Subst

import PlutusCore qualified as PLC
import PlutusCore.Name.Unique qualified as PLC

import Control.Lens

import Data.MultiSet qualified as MSet
import Data.MultiSet.Lens
import Data.Set qualified as Set

type Usages = MSet.MultiSet PLC.Unique

-- | Get the usage count of @n@.
getUsageCount :: (PLC.HasUnique n unique) => n -> Usages -> Int
getUsageCount :: forall n unique. HasUnique n unique => n -> Usages -> Int
getUsageCount n
n = Unique -> Usages -> Int
forall a. Ord a => a -> MultiSet a -> Int
MSet.occur (n
n n -> Getting Unique n Unique -> Unique
forall s a. s -> Getting a s a -> a
^. (unique -> Const Unique unique) -> n -> Const Unique n
forall a unique. HasUnique a unique => Lens' a unique
Lens' n unique
PLC.unique ((unique -> Const Unique unique) -> n -> Const Unique n)
-> ((Unique -> Const Unique Unique)
    -> unique -> Const Unique unique)
-> Getting Unique n Unique
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Unique -> Const Unique Unique) -> unique -> Const Unique unique
forall s t a b. (Coercible s a, Coercible t b) => Iso s t a b
Iso unique unique Unique Unique
coerced)

-- | Get a set of @n@s which are used at least once.
allUsed :: Usages -> Set.Set PLC.Unique
allUsed :: Usages -> Set Unique
allUsed = Usages -> Set Unique
forall a. MultiSet a -> Set a
MSet.toSet

termUsages
    :: (PLC.HasUnique name PLC.TermUnique)
    => Term name uni fun a
    -> Usages
termUsages :: forall name (uni :: * -> *) fun a.
HasUnique name TermUnique =>
Term name uni fun a -> Usages
termUsages = Getting Usages (Term name uni fun a) Unique
-> Term name uni fun a -> Usages
forall a s. Getting (MultiSet a) s a -> s -> MultiSet a
multiSetOf ((name -> Const Usages name)
-> Term name uni fun a -> Const Usages (Term name uni fun a)
forall name (uni :: * -> *) fun ann (f :: * -> *).
(Contravariant f, Applicative f) =>
(name -> f name)
-> Term name uni fun ann -> f (Term name uni fun ann)
vTerm ((name -> Const Usages name)
 -> Term name uni fun a -> Const Usages (Term name uni fun a))
-> ((Unique -> Const Usages Unique) -> name -> Const Usages name)
-> Getting Usages (Term name uni fun a) Unique
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Unique -> Const Usages Unique) -> name -> Const Usages name
forall name unique. HasUnique name unique => Lens' name Unique
Lens' name Unique
PLC.theUnique)