packages feed

hasmtlib-2.3.0: src/Language/Hasmtlib/Lens.hs

{-# LANGUAGE UndecidableInstances #-}

module Language.Hasmtlib.Lens where

import Language.Hasmtlib.Internal.Expr
import Language.Hasmtlib.Type.Expr
import Language.Hasmtlib.Type.SMTSort
import Language.Hasmtlib.Equatable
import Language.Hasmtlib.Orderable
import Language.Hasmtlib.Iteable
import Data.GADT.Compare
import Control.Lens

type instance Index   (Expr StringSort) = Expr IntSort
type instance IxValue (Expr StringSort) = Expr StringSort

instance Ixed (Expr StringSort) where
  ix i f s = f (strAt s i) <&> \a ->
    let l = strSubstring a 0 i
        r = strSubstring a i (strLength a)
     in l <> strReplace r (strAt a i) s

instance AsEmpty (Expr StringSort) where
  _Empty = prism'
    (const mempty)
    (\s -> ite (s === mempty) (Just ()) Nothing)

instance Prefixed (Expr StringSort) where
  prefixed p = prism'
    (p <>)
    (\s -> ite (p `strPrefixOf` s) (Just $ strReplace s p mempty) Nothing)

instance Suffixed (Expr StringSort) where
  suffixed qs = prism'
    (<> qs)
    (\s -> ite (qs `strSuffixOf` s) (Just $ strSubstring s 0 (strLength s - strLength qs)) Nothing)

instance Cons (Expr StringSort) (Expr StringSort) (Expr StringSort) (Expr StringSort) where
  _Cons = prism'
    (uncurry (<>))
    (\s -> ite (strLength s >? 0) (Just (strAt s 0, strSubstring s 1 (strLength s))) Nothing)

instance Snoc (Expr StringSort) (Expr StringSort) (Expr StringSort) (Expr StringSort) where
  _Snoc = prism'
    (uncurry (<>))
    (\s -> ite (strLength s >? 0) (Just (strSubstring s 0 (strLength s - 1), strAt s (strLength s - 1))) Nothing)

type instance Index   (Expr (ArraySort k v)) = Expr k
type instance IxValue (Expr (ArraySort k v)) = Expr v

instance (KnownSMTSort k, KnownSMTSort v, Ord (HaskellType k)) => Ixed (Expr (ArraySort k v)) where
  ix i f arr = f (select arr i) <&> store arr i

-- | **Caution for quantified expressions:** 'plate-function' @f@ will only be applied if quantification already has taken place.(&&)
--   Therefore make sure 'quantify' has been run before.
--   Otherwise the quantified expression and therefore all it's sub-expressions will not have @f@ applied.
instance KnownSMTSort t => Plated (Expr t) where
  plate _ expr@(Var _)            = pure expr
  plate _ expr@(Constant _)       = pure expr
  plate f (Plus x y)              = Plus <$> f x <*> f y
  plate f (Neg x)                 = Neg <$> f x
  plate f (Mul x y)               = Mul <$> f x <*> f y
  plate f (Abs x)                 = Abs <$> f x
  plate f (Mod x y)               = Mod <$> f x <*> f y
  plate f (IDiv x y)              = IDiv <$> f x <*> f y
  plate f (Div x y)               = Div <$> f x <*> f y
  plate f (LTH x y)               = LTH <$> somePlate f x <*> somePlate f y
  plate f (LTHE x y)              = LTHE <$> somePlate f x <*> somePlate f y
  plate f (EQU xs)                = EQU <$> traverse (somePlate f) xs
  plate f (Distinct xs)           = Distinct <$> traverse (somePlate f) xs
  plate f (GTHE x y)              = GTHE <$> somePlate f x <*> somePlate f y
  plate f (GTH x y)               = GTH <$> somePlate f x <*> somePlate f y
  plate f (Not x)                 = Not <$> somePlate f x
  plate f (And x y)               = And <$> somePlate f x <*> somePlate f y
  plate f (Or x y)                = Or <$> somePlate f x <*> somePlate f y
  plate f (Impl x y)              = Impl <$> somePlate f x <*> somePlate f y
  plate f (Xor x y)               = Xor <$> somePlate f x <*> somePlate f y
  plate _ Pi                      = pure Pi
  plate f (Sqrt x)                = Sqrt <$> f x
  plate f (Exp x)                 = Exp <$> f x
  plate f (Sin x)                 = Sin <$> f x
  plate f (Cos x)                 = Cos <$> f x
  plate f (Tan x)                 = Tan <$> f x
  plate f (Asin x)                = Asin <$> f x
  plate f (Acos x)                = Acos <$> f x
  plate f (Atan x)                = Atan <$> f x
  plate f (ToReal x)              = ToReal <$> somePlate f x
  plate f (ToInt x)               = ToInt <$> somePlate f x
  plate f (IsInt x)               = IsInt <$> somePlate f x
  plate f (Ite p t n)             = Ite <$> somePlate f p <*> f t <*> f n
  plate f (BvNot x)               = BvNot <$> f x
  plate f (BvAnd x y)             = BvAnd <$> f x <*> f y
  plate f (BvOr x y)              = BvOr <$> f x <*> f y
  plate f (BvXor x y)             = BvXor <$> f x <*> f y
  plate f (BvNand x y)            = BvNand <$> f x <*> f y
  plate f (BvNor x y)             = BvNor <$> f x <*> f y
  plate f (BvNeg x)               = BvNeg <$> f x
  plate f (BvAdd x y)             = BvAdd <$> f x <*> f y
  plate f (BvSub x y)             = BvSub <$> f x <*> f y
  plate f (BvMul x y)             = BvMul <$> f x <*> f y
  plate f (BvuDiv x y)            = BvuDiv <$> f x <*> f y
  plate f (BvuRem x y)            = BvuRem <$> f x <*> f y
  plate f (BvShL x y)             = BvShL <$> f x <*> f y
  plate f (BvLShR x y)            = BvLShR <$> f x <*> f y
  plate f (BvConcat x y)          = BvConcat <$> somePlate f x <*> somePlate f y
  plate f (BvRotL i x)            = BvRotL i <$> f x
  plate f (BvRotR i x)            = BvRotR i <$> f x
  plate f (BvuLT x y)             = BvuLT <$> somePlate f x <*> somePlate f y
  plate f (BvuLTHE x y)           = BvuLTHE <$> somePlate f x <*> somePlate f y
  plate f (BvuGTHE x y)           = BvuGTHE <$> somePlate f x <*> somePlate f y
  plate f (BvuGT x y)             = BvuGT <$> somePlate f x <*> somePlate f y
  plate f (ArrSelect i arr)       = ArrSelect i <$> somePlate f arr
  plate f (ArrStore i x arr)      = ArrStore i <$> somePlate f x <*> somePlate f arr
  plate f (StrConcat x y)         = StrConcat <$> f x <*> f y
  plate f (StrLength x)           = StrLength <$> somePlate f x
  plate f (StrLT x y)             = StrLT <$> somePlate f x <*> somePlate f y
  plate f (StrLTHE x y)           = StrLTHE <$> somePlate f x <*> somePlate f y
  plate f (StrAt x i)             = StrAt <$> f x <*> somePlate f i
  plate f (StrSubstring x i j)    = StrSubstring <$> f x <*> somePlate f i <*> somePlate f j
  plate f (StrPrefixOf x y)       = StrPrefixOf <$> somePlate f x <*> somePlate f y
  plate f (StrSuffixOf x y)       = StrSuffixOf <$> somePlate f x <*> somePlate f y
  plate f (StrContains x y)       = StrContains <$> somePlate f x <*> somePlate f y
  plate f (StrIndexOf x y i)      = StrIndexOf <$> somePlate f x <*> somePlate f y <*> f i
  plate f (StrReplace x y y')     = StrReplace <$> f x <*> f y <*> f y'
  plate f (StrReplaceAll x y y')  = StrReplaceAll <$> f x <*> f y <*> f y'
  plate f (ForAll (Just qv) expr) = ForAll (Just qv) . const <$> somePlate f (expr (Var qv))
  plate _ (ForAll Nothing expr)   = pure $ ForAll Nothing expr
  plate f (Exists (Just qv) expr) = Exists (Just qv) . const <$> somePlate f (expr (Var qv))
  plate _ (Exists Nothing expr)   = pure $ Exists Nothing expr

-- | Apply the 'plate'-function @f@ for given 'Expr' @expr@ if possible.
--   Otherwise try to apply @f@ for the children of @expr@.
--   **Caution for quantified expressions:** 'plate-function' @f@ will only be applied if quantification already has taken place.(&&)
--   Therefore make sure 'quantify' has been run before.
--   Otherwise the quantified expression and therefore all it's sub-expressions will not have @f@ applied.
somePlate :: forall t f. (KnownSMTSort t, Applicative f) => (Expr t -> f (Expr t)) -> (forall s. KnownSMTSort s => Expr s -> f (Expr s))
somePlate f expr = case geq (sortSing @t) (sortSing' expr) of
  Just Refl -> f expr
  Nothing   -> case expr of
    Var _                -> pure expr
    Constant _           -> pure expr
    Plus x y             -> Plus <$> somePlate f x <*> somePlate f y
    Neg x                -> Neg  <$> somePlate f x
    Mul x y              -> Mul  <$> somePlate f x <*> somePlate f y
    Abs x                -> Abs  <$> somePlate f x
    Mod x y              -> Mod  <$> somePlate f x <*> somePlate f y
    IDiv x y             -> IDiv <$> somePlate f x <*> somePlate f y
    Div x y              -> Div  <$> somePlate f x <*> somePlate f y
    LTH x y              -> LTH  <$> somePlate f x <*> somePlate f y
    LTHE x y             -> LTHE <$> somePlate f x <*> somePlate f y
    EQU xs               -> EQU  <$> traverse (somePlate f) xs
    Distinct xs          -> Distinct <$> traverse (somePlate f) xs
    GTHE x y             -> GTHE <$> somePlate f x <*> somePlate f y
    GTH x y              -> GTH  <$> somePlate f x <*> somePlate f y
    Not x                -> Not  <$> somePlate f x
    And x y              -> And  <$> somePlate f x <*> somePlate f y
    Or x y               -> Or   <$> somePlate f x <*> somePlate f y
    Impl x y             -> Impl <$> somePlate f x <*> somePlate f y
    Xor x y              -> Xor  <$> somePlate f x <*> somePlate f y
    Pi                   -> pure Pi
    Sqrt x               -> Sqrt <$> somePlate f x
    Exp x                -> Exp  <$> somePlate f x
    Sin x                -> Sin  <$> somePlate f x
    Cos x                -> Cos  <$> somePlate f x
    Tan x                -> Tan  <$> somePlate f x
    Asin x               -> Asin <$> somePlate f x
    Acos x               -> Acos <$> somePlate f x
    Atan x               -> Atan <$> somePlate f x
    ToReal x             -> ToReal <$> somePlate f x
    ToInt x              -> ToInt  <$> somePlate f x
    IsInt x              -> IsInt  <$> somePlate f x
    Ite p t n            -> Ite    <$> somePlate f p <*> somePlate f t <*> somePlate f n
    BvNot x              -> BvNot  <$> somePlate f x
    BvAnd x y            -> BvAnd  <$> somePlate f x <*> somePlate f y
    BvOr x y             -> BvOr   <$> somePlate f x <*> somePlate f y
    BvXor x y            -> BvXor  <$> somePlate f x <*> somePlate f y
    BvNand x y           -> BvNand <$> somePlate f x <*> somePlate f y
    BvNor x y            -> BvNor  <$> somePlate f x <*> somePlate f y
    BvNeg x              -> BvNeg  <$> somePlate f x
    BvAdd x y            -> BvAdd  <$> somePlate f x <*> somePlate f y
    BvSub x y            -> BvSub  <$> somePlate f x <*> somePlate f y
    BvMul x y            -> BvMul  <$> somePlate f x <*> somePlate f y
    BvuDiv x y           -> BvuDiv <$> somePlate f x <*> somePlate f y
    BvuRem x y           -> BvuRem <$> somePlate f x <*> somePlate f y
    BvShL x y            -> BvShL  <$> somePlate f x <*> somePlate f y
    BvLShR x y           -> BvLShR <$> somePlate f x <*> somePlate f y
    BvConcat x y         -> BvConcat <$> somePlate f x <*> somePlate f y
    BvRotL i x           -> BvRotL i <$> somePlate f x
    BvRotR i x           -> BvRotR i <$> somePlate f x
    BvuLT x y            -> BvuLT    <$> somePlate f x <*> somePlate f y
    BvuLTHE x y          -> BvuLTHE  <$> somePlate f x <*> somePlate f y
    BvuGTHE x y          -> BvuGTHE  <$> somePlate f x <*> somePlate f y
    BvuGT x y            -> BvuGT    <$> somePlate f x <*> somePlate f y
    ArrSelect i arr      -> ArrSelect i   <$> somePlate f arr
    ArrStore i x arr     -> ArrStore i    <$> somePlate f x <*> somePlate f arr
    StrConcat x y        -> StrConcat     <$> somePlate f x <*> somePlate f y
    StrLength x          -> StrLength     <$> somePlate f x
    StrLT x y            -> StrLT         <$> somePlate f x <*> somePlate f y
    StrLTHE x y          -> StrLTHE       <$> somePlate f x <*> somePlate f y
    StrAt x i            -> StrAt         <$> somePlate f x <*> somePlate f i
    StrSubstring x i j   -> StrSubstring  <$> somePlate f x <*> somePlate f i <*> somePlate f j
    StrPrefixOf x y      -> StrPrefixOf   <$> somePlate f x <*> somePlate f y
    StrSuffixOf x y      -> StrSuffixOf   <$> somePlate f x <*> somePlate f y
    StrContains x y      -> StrContains   <$> somePlate f x <*> somePlate f y
    StrIndexOf x y i     -> StrIndexOf    <$> somePlate f x <*> somePlate f y <*> somePlate f i
    StrReplace x y y'    -> StrReplace    <$> somePlate f x <*> somePlate f y <*> somePlate f y'
    StrReplaceAll x y y' -> StrReplaceAll <$> somePlate f x <*> somePlate f y <*> somePlate f y'
    ForAll (Just qv) qexpr -> ForAll (Just qv) . const <$> somePlate f (qexpr (Var qv))
    ForAll Nothing qexpr   -> pure $ ForAll Nothing qexpr
    Exists (Just qv) qexpr -> Exists (Just qv) . const <$> somePlate f (qexpr (Var qv))
    Exists Nothing qexpr   -> pure $ Exists Nothing qexpr