never executed always true always false
    1 {-# LANGUAGE AllowAmbiguousTypes #-}
    2 {-# LANGUAGE DuplicateRecordFields #-}
    3 {-# LANGUAGE GADTs #-}
    4 
    5 {- |
    6 Module      : NITTA.Intermediate.Functions
    7 Description : Accum function
    8 Copyright   : (c) Daniil Prohorov, 2019
    9 License     : BSD3
   10 Maintainer  : aleksandr.penskoi@gmail.com
   11 Stability   : experimental
   12 -}
   13 module NITTA.Intermediate.Functions.Accum (
   14     Acc (..),
   15     Action (..),
   16     Sign (..),
   17 
   18     -- * Acc to function
   19     acc,
   20     accFromStr,
   21 
   22     -- * Utils functions
   23     isPull,
   24     isPush,
   25 ) where
   26 
   27 import Data.List (nub, partition)
   28 import Data.List.Split (splitWhen)
   29 import Data.Set qualified as S
   30 import Data.String.ToString
   31 import Data.String.Utils qualified as S
   32 import Data.Text qualified as T
   33 import Data.Typeable
   34 import NITTA.Intermediate.Types
   35 import NITTA.Utils.Base
   36 import Text.Regex
   37 
   38 data Sign = Plus | Minus deriving (Typeable, Eq)
   39 
   40 instance Show Sign where
   41     show Plus = "+"
   42     show Minus = "-"
   43 
   44 data Action v = Push Sign (I v) | Pull (O v) deriving (Typeable, Eq)
   45 
   46 instance Var v => Show (Action v) where
   47     show (Push s (I v)) = show s <> toString v
   48     show (Pull (O vs)) = S.join " " $ map ("= " <>) $ vsToStringList vs
   49 
   50 instance Variables (Action v) v where
   51     variables (Push _s i) = variables i
   52     variables (Pull o) = variables o
   53 
   54 newtype Acc v x = Acc {actions :: [Action v]} deriving (Typeable, Eq)
   55 
   56 instance Var v => Show (Acc v x) where
   57     show (Acc acts) =
   58         let lastElement = last acts
   59             initElements = init acts
   60             showElement inp@(Push _ _) = show inp
   61             showElement out@(Pull _) = show out <> ","
   62             elements = S.join " " $ map showElement initElements <> [show lastElement]
   63          in "Acc(" <> elements <> ")"
   64 
   65 instance Label (Acc v x) where label Acc{} = "Acc"
   66 
   67 -- | Create function with type F of Acc
   68 acc lst = packF $ Acc lst
   69 
   70 -- | Special function for generating Acc from string, examples in tests
   71 accFromStr desc = packF $ accGen $ toBlocksSplit desc
   72 
   73 isPull Pull{} = True
   74 isPull _ = False
   75 
   76 isPush Push{} = True
   77 isPush _ = False
   78 
   79 fromPush (Push _ (I v)) = v
   80 fromPush _ = error "Error in fromPush function in acc"
   81 
   82 fromPull (Pull (O vs)) = vs
   83 fromPull _ = error "Error in fromPull function in acc"
   84 
   85 instance Ord v => Function (Acc v x) v where
   86     inputs (Acc lst) = S.fromList $ map fromPush $ filter isPush lst
   87     outputs (Acc lst) = unionsMap fromPull $ filter isPull lst
   88 
   89 instance Ord v => Patch (Acc v x) (v, v) where
   90     patch diff (Acc lst) =
   91         Acc $
   92             nub $
   93                 map
   94                     ( \case
   95                         Push s v -> Push s (patch diff v)
   96                         Pull vs -> Pull (patch diff vs)
   97                     )
   98                     lst
   99 
  100 exprPattern = mkRegex "[+,=,-]*[a-zA-Z0-9]+|;"
  101 toBlocksSplit exprInput =
  102     let splitBySemicolon = filter (not . null) . splitWhen (== ";")
  103         matchAll p inpS res =
  104             case matchRegexAll p inpS of
  105                 Just (_, x, xs, _) -> x : matchAll p xs res
  106                 Nothing -> []
  107         filtered = subRegex (mkRegex "[ ]+") exprInput ""
  108      in splitBySemicolon $ matchAll exprPattern filtered []
  109 
  110 accGen blocks =
  111     let partedExpr =
  112             map
  113                 ( partition $ \case
  114                     (x : _) -> x /= '='
  115                     x -> error $ "error in accGen: " <> show x
  116                 )
  117         signPush ('+' : name) = Push Plus (I $ T.pack name)
  118         signPush ('-' : name) = Push Minus (I $ T.pack name)
  119         signPush _ = error "Error in matching + and -"
  120         pushCreate lst = map signPush lst
  121         pullCreate lst =
  122             Pull $
  123                 O $
  124                     S.fromList $
  125                         foldl
  126                             ( \buff -> \case
  127                                 (_ : name) -> T.pack name : buff
  128                                 _ -> error "accGen internal error"
  129                             )
  130                             []
  131                             lst
  132      in Acc $ concatMap (\(push, pull) -> pushCreate push ++ [pullCreate pull]) $ partedExpr blocks
  133 
  134 instance Var v => Locks (Acc v x) v where
  135     locks (Acc actions) =
  136         let (lockByActions, lockedActions) = span isPush actions
  137          in [ Lock{locked, lockBy}
  138             | locked <- S.elems $ unionsMap variables lockedActions
  139             , lockBy <- S.elems $ unionsMap variables lockByActions
  140             ]
  141 
  142 instance (Var v, Num x) => FunctionSimulation (Acc v x) v x where
  143     simulate cntx (Acc ops) = snd $ foldl eval (0, []) ops
  144         where
  145             eval (buf, changes) (Push sign (I v))
  146                 | x <- getCntx cntx v =
  147                     case sign of
  148                         Plus -> (buf + x, changes)
  149                         Minus -> (buf - x, changes)
  150             eval (buf, changes) (Pull (O vs)) = (buf, [(v, buf) | v <- S.elems vs] ++ changes)