{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE ScopedTypeVariables #-}
module UntypedPlutusCore.Check.Scope (checkScope, ScopeCheckMode (..)) where
import Control.Lens hiding (index)
import UntypedPlutusCore.Core.Type as UPLC
import UntypedPlutusCore.DeBruijn as UPLC
import Control.Monad (unless)
import Control.Monad.Except (MonadError, throwError)
data ScopeCheckMode
= NoCaseConstr
| Full
checkScope
:: forall m name uni fun a
. (HasIndex name, MonadError FreeVariableError m)
=> ScopeCheckMode
-> UPLC.Term name uni fun a
-> m ()
checkScope :: forall (m :: * -> *) name (uni :: * -> *) fun a.
(HasIndex name, MonadError FreeVariableError m) =>
ScopeCheckMode -> Term name uni fun a -> m ()
checkScope ScopeCheckMode
mode = Word -> Term name uni fun a -> m ()
go Word
0
where
go :: Word -> UPLC.Term name uni fun a -> m ()
go :: Word -> Term name uni fun a -> m ()
go !Word
lvl = \case
Var a
_ name
n -> do
let i :: Index
i = name
n name -> Getting Index name Index -> Index
forall s a. s -> Getting a s a -> a
^. Getting Index name Index
forall a. HasIndex a => Lens' a Index
Lens' name Index
index
Bool -> m () -> m ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless (Index
i Index -> Index -> Bool
forall a. Ord a => a -> a -> Bool
> Index
0 Bool -> Bool -> Bool
&& Index -> Word
forall a b. (Integral a, Num b) => a -> b
fromIntegral Index
i Word -> Word -> Bool
forall a. Ord a => a -> a -> Bool
<= Word
lvl) (m () -> m ()) -> m () -> m ()
forall a b. (a -> b) -> a -> b
$
FreeVariableError -> m ()
forall a. FreeVariableError -> m a
forall e (m :: * -> *) a. MonadError e m => e -> m a
throwError (FreeVariableError -> m ()) -> FreeVariableError -> m ()
forall a b. (a -> b) -> a -> b
$
Index -> FreeVariableError
FreeIndex Index
i
LamAbs a
_ name
binder Term name uni fun a
t -> do
let bIx :: Index
bIx = name
binder name -> Getting Index name Index -> Index
forall s a. s -> Getting a s a -> a
^. Getting Index name Index
forall a. HasIndex a => Lens' a Index
Lens' name Index
index
Bool -> m () -> m ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless (Index
bIx Index -> Index -> Bool
forall a. Eq a => a -> a -> Bool
== Index
0) (m () -> m ()) -> m () -> m ()
forall a b. (a -> b) -> a -> b
$
FreeVariableError -> m ()
forall a. FreeVariableError -> m a
forall e (m :: * -> *) a. MonadError e m => e -> m a
throwError (FreeVariableError -> m ()) -> FreeVariableError -> m ()
forall a b. (a -> b) -> a -> b
$
Index -> FreeVariableError
FreeIndex Index
bIx
Word -> Term name uni fun a -> m ()
go (Word
lvl Word -> Word -> Word
forall a. Num a => a -> a -> a
+ Word
1) Term name uni fun a
t
Apply a
_ Term name uni fun a
t1 Term name uni fun a
t2 -> Word -> Term name uni fun a -> m ()
go Word
lvl Term name uni fun a
t1 m () -> m () -> m ()
forall a b. m a -> m b -> m b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> Word -> Term name uni fun a -> m ()
go Word
lvl Term name uni fun a
t2
Force a
_ Term name uni fun a
t -> Word -> Term name uni fun a -> m ()
go Word
lvl Term name uni fun a
t
Delay a
_ Term name uni fun a
t -> Word -> Term name uni fun a -> m ()
go Word
lvl Term name uni fun a
t
Constr a
_ Word64
_ [Term name uni fun a]
ts ->
case ScopeCheckMode
mode of
ScopeCheckMode
Full -> (Term name uni fun a -> m ()) -> [Term name uni fun a] -> m ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_ (Word -> Term name uni fun a -> m ()
go Word
lvl) [Term name uni fun a]
ts
ScopeCheckMode
NoCaseConstr -> () -> m ()
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure ()
Case a
_ Term name uni fun a
t Vector (Term name uni fun a)
ts ->
case ScopeCheckMode
mode of
ScopeCheckMode
Full -> Word -> Term name uni fun a -> m ()
go Word
lvl Term name uni fun a
t m () -> m () -> m ()
forall a b. m a -> m b -> m b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> (Term name uni fun a -> m ())
-> Vector (Term name uni fun a) -> m ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_ (Word -> Term name uni fun a -> m ()
go Word
lvl) Vector (Term name uni fun a)
ts
ScopeCheckMode
NoCaseConstr -> () -> m ()
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure ()
Constant a
_ Some (ValueOf uni)
_ -> () -> m ()
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure ()
Error a
_ -> () -> m ()
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure ()
Builtin a
_ fun
_ -> () -> m ()
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure ()
{-# INLINE checkScope #-}