blob: e7b0fca705d738eabd1dac9ffefc9e39f714009a [file]
{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DisambiguateRecordFields #-}
{-# LANGUAGE DuplicateRecordFields #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE ForeignFunctionInterface #-}
{-# LANGUAGE ImplicitParams #-}
{- LANGUAGE ImplicitPrelude #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE MultiWayIf #-}
{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE NoMonomorphismRestriction #-}
{-# LANGUAGE PartialTypeSignatures #-}
{- LANGUAGE RebindableSyntax #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE ScopedTypeVariables #-}
{- LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE TypeSynonymInstances #-}
{-# OPTIONS_GHC -Wno-missing-fields #-}
{- OPTIONS_GHC -F -pgmFderive -optF-F #-}
module WordArraySimple where
import Control.Exception (bracket)
import Control.Lens hiding (elements)
-- import Control.Monad.State
import Control.Monad (void)
import Control.Monad.Trans.Class (lift)
import Data.Either.Extra -- extra-1.6
-- import Data.Function
import Data.Functor.Classes
import Data.Ix
import Data.List (genericDrop, genericTake)
import qualified Data.Set as S
-- import qualified Data.Set.Internal as S
import Enumerate
import Foreign hiding (void)
import Foreign.C.String hiding (CString)
import Foreign.C.Types
import Foreign.ForeignPtr
import Foreign.Marshal.Alloc
import Foreign.Marshal.Unsafe (unsafeLocalState)
import Foreign.Ptr
import Foreign.Storable
import GHC.Generics
import Prelude as P
-- import QuickCheck.GenT
import Test.QuickCheck hiding (Success)
import Test.QuickCheck.Arbitrary
import Test.QuickCheck.Function
import Test.QuickCheck.Gen
import Test.QuickCheck.Monadic
import CogentMonad
import Corres
import Wa_FFI_Types
import Wa_FFI_Types_Abs
import Wa_FFI
import Util
-- import Debug.Trace
{- |
To run the REPL:
> cabal v1-repl wa-example --ghc-options=" wa_example/build/wa.o"
-}
-- * Haskell specification
-- | The Haskell type for wordarrays
type WordArray e = [e]
data O = O_mallocFail
| O_zeroLengthFail
| O_good
deriving (Show, Generic, Enumerable)
empty_array :: WordArray e
empty_array = []
hs_wordarray_create :: (?o :: O, Integral e) => Word32 -> Maybe (WordArray e)
hs_wordarray_create l
| O_mallocFail <- ?o = Nothing
| otherwise = Just $ replicate (fromIntegral l) 0
hs_wordarray_create_nd :: (Integral e) => Word32 -> CogentMonad (Maybe (WordArray e))
hs_wordarray_create_nd 0 = return Nothing <|> return (Just []) -- either nothing or empty array
hs_wordarray_create_nd l = return Nothing <|> return (Just (replicate (fromIntegral l) 0))
hs_wordarray_create_nz :: (Integral e, ?o :: O) => Word32 -> Maybe (WordArray e)
hs_wordarray_create_nz l
| O_mallocFail <- ?o = Nothing
| otherwise = Just $ replicate (fromIntegral l) 0
hs_wordarray_free :: WordArray e -> ()
hs_wordarray_free _ = ()
hs_wordarray_get_bounded :: Integral e => WordArray e -> Word32 -> Maybe e
hs_wordarray_get_bounded xs i =
if i `is_inbound` xs then Just $ xs !! (fromIntegral i) else Nothing
is_inbound :: Word32 -> WordArray e -> Bool
is_inbound i xs = i >= 0 && i < fromIntegral (length xs)
hs_wordarray_modify :: WordArray e
-> Word32
-> ((e, acc, obsv) -> (e, acc))
-> acc
-> obsv
-> (WordArray e, acc)
hs_wordarray_modify xs i f acc obsv
| i `is_inbound` xs =
let (e',acc') = f (xs !! fromIntegral i, acc, obsv)
in (list_update xs i e', acc')
| otherwise = P.error "out-of-bound index not allowed in wordarray_modify"
-- | __NOTE__: We also need to specify all inner functions used. As on the Cogent
-- side, due to the way higher-order function calls are made, we cannot generate
-- random functions for testing. The way we test higher-order functions is
-- to show that for all callable inner functions, the outer function behaves
-- correctly.
--
-- In the case of @wordarray_modify@, @modify_bofy_f@ is the only callable
-- function. This can be seem in the @dispatch@ functions generated in the .h file. / zilinc
hs_modify_body_f :: (Word8, Word8, Bool) -> (Word8, Word8)
hs_modify_body_f (e, acc, obsv) =
if obsv then (e + acc, e + acc) else (e, acc)
hs_wordarray_put :: WordArray e -> Word32 -> e -> Either (WordArray e) (WordArray e)
hs_wordarray_put xs i _ | not (i `is_inbound` xs) = Left xs
hs_wordarray_put xs i a = Right $ list_update xs i a
hs_wordarray_length :: WordArray e -> Word32
hs_wordarray_length = fromIntegral . length
hs_wordarray_clone :: (?o :: O) => WordArray e -> Maybe (WordArray e)
hs_wordarray_clone xs
| O_mallocFail <- ?o = Nothing
| otherwise = Just xs
hs_wordarray_set :: WordArray a -> Word32 -> Word32 -> a -> WordArray a
hs_wordarray_set arr frm n a
| fromIntegral frm > length arr = arr
| fromIntegral (frm + n) > length arr = take (fromIntegral frm) arr ++ replicate (length arr - fromIntegral frm) a
| otherwise = take (fromIntegral frm) arr ++ replicate (fromIntegral n) a ++ drop (fromIntegral $ frm + n) arr
-- /////////////////////////////////////////////////////////////////////////////
--
-- * Testing @wordarray_set@
prop_corres_wordarray_set_u8 :: Property
prop_corres_wordarray_set_u8 = monadicIO $
forAllM gen_wordarray_set_u8_arg' $ \ia -> run $ do
let oa = uncurry4 hs_wordarray_set ia
ic <- mk_c_wordarray_set_u8_arg ia
oc <- cogent_wordarray_set_u8 ic
corresM' rel_wordarray_u8 oa oc
rel_wordarray_u8 :: WordArray Word8 -> Ptr (CWordArray_u8) -> IO Bool
rel_wordarray_u8 hs_arr c_arr = do
CWordArray_u8 len pvalues <- peek c_arr
arr <- peekArray (fromIntegral len) pvalues
return $ map fromIntegral hs_arr == arr
gen_wordarray_set_u8_arg' :: Gen ([Word8], Word32, Word32, Word8)
gen_wordarray_set_u8_arg' = do
l <- choose (1, 200) :: Gen Word32
arr <- vector $ fromIntegral l
frm <- choose (0, 250)
n <- choose (0, 150)
a <- arbitrary :: Gen Word8
return (arr, frm, n, a)
mk_c_wordarray_set_u8_arg :: ([Word8], Word32, Word32, Word8) -> IO (Ptr Ct5)
mk_c_wordarray_set_u8_arg (arr, frm, n, a) = do
p_arr <- mk_c_wordarray_u8 arr
new $ Ct5 p_arr (fromIntegral frm) (fromIntegral n) (fromIntegral a)
mk_c_wordarray_u8 :: [Word8] -> IO (Ptr CWordArray_u8)
mk_c_wordarray_u8 elems = do
let l = length elems
pvalues <- newArray (map fromIntegral elems :: [Cu8])
new $ CWordArray_u8 (fromIntegral l) pvalues
-- /////////////////////////////////////////////////////////////////////////////
--
-- * Helper functions
list_update :: (Integral n) => [a] -> n -> a -> [a]
list_update [] i v = []
list_update (x:xs) i v =
case i of 0 -> v:xs
k | k > 0 -> x : list_update xs (k-1) v
k -> P.error "negative index"
-- /////////////////////////////////////////////////////////////////////////////
--
-- * Main function
return []
main = $quickCheckAll