{-# LANGUAGE QuasiQuotes #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TypeOperators #-} -- | Tests for various constructs module Imperative where import Data.Int import Data.Word import Language.Embedded.Imperative import Language.Embedded.Backend.C import Language.Embedded.CExp type CMD = RefCMD :+: ArrCMD :+: ControlCMD :+: PtrCMD :+: FileCMD :+: C_CMD type Prog = Program CMD (Param2 CExp CType) prog :: Prog () prog = do r <- initRef (10 :: CExp Int32) a <- getRef r modifyRef r (*a) printf "%d\n" a -- | Test primitive types testTypes :: Prog () testTypes = do inp :: CExp Int32 <- fget stdin a <- unsafeFreezeRef =<< initRef (i2n inp + 0x88 :: CExp Int8) b <- unsafeFreezeRef =<< initRef (i2n inp + 0x8888 :: CExp Int16) c <- unsafeFreezeRef =<< initRef (i2n inp + 0x88888888 :: CExp Int32) d <- unsafeFreezeRef =<< initRef (i2n inp + 0x8888888888888888 :: CExp Int64) e <- unsafeFreezeRef =<< initRef (i2n inp + 0xEE :: CExp Word8) f <- unsafeFreezeRef =<< initRef (i2n inp + 0xEEEE :: CExp Word16) g <- unsafeFreezeRef =<< initRef (i2n inp + 0xEEEEEEEE :: CExp Word32) h <- unsafeFreezeRef =<< initRef (i2n inp + 0xEEEEEEEEEEEEEEEE :: CExp Word64) i <- unsafeFreezeRef =<< initRef (i2n inp - 9 :: CExp Float) j <- unsafeFreezeRef =<< initRef (i2n inp - 10 :: CExp Double) printf "%d %d %d %ld %u %u %u %lu %.3f %.3f\n" a b c d e f g h i j k1 <- unsafeFreezeRef =<< initRef true k2 <- unsafeFreezeRef =<< initRef true iff ((k1 #&& k2) #|| not_ k1) (printf "true") (printf "false") testCExp :: Prog () testCExp = do a :: CExp Int32 <- fget stdin let b = a#==10 ? a*3 $ a-5+8 let c = sin (i2n a) :: CExp Double let d = c/23 printf "%d " b printf "%d " (not_ (a#==10) ? a*3 $ a-5+8) printf "%d " (a `quot_` b) printf "%d " (a #% b) printf "%d " (cond (i2b a) a b) printf "%d " (b2i (not_ (a#==10)) * a) printf "%.3f " c printf "%.3f " d printf "%.3f " (i2n a :: CExp Float) printf "%ld " (round_ (c*1000) :: CExp Int32) printf "%d " (round_ (11.5 :: CExp Float) :: CExp Int32) printf "%d " (round_ (-11.5 :: CExp Float) :: CExp Int32) printf "%.3f " (c**d) testRef :: Prog () testRef = do r1 <- newRef r2 <- initRef (3 :: CExp Int32) modifyRef r2 (*2) setRef r1 =<< getRef r2 a <- unsafeFreezeRef r1 b <- unsafeFreezeRef r2 printf "%d %d\n" a b testArr1 :: Prog () testArr1 = do arr1 :: Arr Word32 Int32 <- newArr (10 :: CExp Word32) arr2 :: Arr Word32 Int32 <- newArr (10 :: CExp Word32) sequence_ [setArr i (i2n i+10) arr1 | i' <- [0..9], let i = fromInteger i'] copyArr arr2 arr1 10 sequence_ [getArr i arr2 >>= printf "%d " . (*3) | i' <- [0..9], let i = fromInteger i'] printf "\n" testArr2 :: Prog () testArr2 = do n <- fget stdin arr :: Arr Word32 Int32 <- newArr n -- Array of dynamic length sequence_ [setArr (i2n i) i arr | i' <- [0..3], let i = fromInteger i'] sequence_ [getArr i arr >>= printf "%d " . (*3) | i' <- [0..3], let i = fromInteger i'] printf "\n" return () testArr3 :: Prog () testArr3 = do arr :: Arr Word32 Int32 <- initArr [8,7,6,5] sequence_ [getArr i arr >>= printf "%d " . (*3) | i' <- [0..3], let i = fromInteger i'] printf "\n" return () testArr4 :: Prog () testArr4 = do arr :: Arr Word32 Int32 <- initArr [8,7,6,5] iarr <- freezeArr arr 4 sequence_ [printf "%d " $ iarr #! i | i' <- [0..3], let i = fromInteger i'] printf "\n" testArr5 :: Prog () testArr5 = do arr :: Arr Word32 Int32 <- initArr [8,7,6,5] iarr <- unsafeFreezeArr arr sequence_ [printf "%d " $ iarr #! i | i' <- [0..3], let i = fromInteger i'] printf "\n" testArr6 :: Prog () testArr6 = do arr :: Arr Word32 Int32 <- initArr [8,7,6,5] iarr <- unsafeFreezeArr arr arr2 <- unsafeThawArr iarr sequence_ [getArr i arr2 >>= printf "%d " | i <- map fromInteger [0..3]] printf "\n" testArr7 :: Prog () testArr7 = do arr :: Arr Word32 Int32 <- initArr [8,7,6,5] iarr <- freezeArr arr 4 arr2 <- thawArr iarr 4 sequence_ [getArr i arr2 >>= printf "%d " | i <- map fromInteger [0..3]] printf "\n" testSwap1 :: Prog () testSwap1 = do arr1 :: Arr Word32 Int32 <- initArr [1,2,3,4] arr2 :: Arr Word32 Int32 <- initArr [11,12,13,14] unsafeSwap arr1 arr2 sequence_ [getArr i arr1 >>= printf "%d " | i <- map fromInteger [0..3]] printf "\n" testSwap2 :: Prog () testSwap2 = do arr1 :: Arr Word32 Int32 <- initArr [1,2,3,4] n <- fget stdin arr2 :: Arr Word32 Int32 <- newArr n copyArr arr2 arr1 4 setArr 2 22 arr2 unsafeSwap arr1 arr2 sequence_ [getArr i arr1 >>= printf "%d " | i <- map fromInteger [0..3]] printf "\n" sequence_ [getArr i arr2 >>= printf "%d " | i <- map fromInteger [0..3]] printf "\n" testIf1 :: Prog () testIf1 = do inp :: CExp Int32 <- fget stdin a <- ifE (inp #== 10) (return (inp+1)) (return (inp*3)) b <- ifE (not_ (inp #== 10)) (return (a+1)) (return (a*3)) printf "%d %d\n" a b testIf2 :: Prog () testIf2 = do inp :: CExp Int32 <- fget stdin iff (inp #== 11) (printf "== 11\n") (printf "/= 11\n") iff (not_ (inp #== 11)) (printf "/= 11\n") (printf "== 11\n") iff (inp #== 12) (printf "== 12\n") (return ()) iff (not_ (inp #== 12)) (return ()) (printf "== 12\n") iff (inp #== 13) (printf "== 13\n") (return ()) iff (not_ (inp #== 13)) (return ()) (printf "== 13\n") iff (inp #== 14) (return ()) (return ()) -- Loop from 0 to 9 in steps of 1 testFor1 :: Prog () testFor1 = for (0,1,9) $ \i -> printf "%d\n" (i :: CExp Int8) -- Loop from 9 to 0 in steps of 2 testFor2 :: Prog () testFor2 = for (9,-2,0) $ \i -> printf "%d\n" (i :: CExp Int8) -- Loop from 0 to but excluding 10 in steps of 2 testFor3 :: Prog () testFor3 = for (0, 2, Excl 10) $ \i -> printf "%d\n" (i :: CExp Int8) -- While loop tested in `sumInput` in Demo.hs. testAssert :: Prog () testAssert = do inp :: CExp Int32 <- fget stdin assert (inp #> 0) "input too small" printf "past assertion\n" testPtr :: Prog () testPtr = do addInclude "" addInclude "" addInclude "" p :: Ptr Int32 <- newPtr callProcAssign p "malloc" [valArg (100 :: CExp Word32)] arr :: Arr Word32 Int32 <- initArr [34,45,56,67,78] callProc "memcpy" [ptrArg p, arrArg arr, valArg (5*4 :: CExp Word32)] -- sizeof(int32_t) = 4 callProc "printf" [strArg "%d\n", deref $ ptrArg p] iarr :: IArr Word32 Int32 <- unsafeFreezeArr =<< ptrToArr p printf "sum: %d\n" (iarr#!0 + iarr#!1 + iarr#!2 + iarr#!3 + iarr#!4) callProc "free" [ptrArg p] testArgs :: Prog () testArgs = do addInclude "" addDefinition setPtr_def addDefinition ret_def let v = 55 :: CExp Int32 r <- initRef (66 :: CExp Int32) a :: Arr Int32 Int32 <- initArr [234..300] ia <- freezeArr a 10 p :: Ptr Int32 <- newPtr o <- newObject "int" False op <- newObject "int" True callProcAssign p "setPtr" [refArg r] callProcAssign o "ret" [valArg v] callProcAssign op "setPtr" [refArg r] callProc "printf" [ strArg "%d %d %d %d %d %d %d\n" , valArg v , deref (refArg r) , deref (arrArg a) , deref (iarrArg ia) , deref (ptrArg p) , objArg o , deref (objArg op) ] where setPtr_def = [cedecl| int * setPtr (int *a) { return a; } |] ret_def = [cedecl| int ret (int a) { return a; } |] testExternArgs :: Prog () testExternArgs = do let v = 55 :: CExp Int32 externProc "val_proc" [valArg v] r <- initRef v externProc "ref_proc1" [refArg r] externProc "ref_proc2" [deref $ refArg r] -- TODO Simplify a :: Arr Int32 Int32 <- newArr 10 externProc "arr_proc1" [arrArg a] externProc "arr_proc2" [addr $ arrArg a] externProc "arr_proc3" [deref $ arrArg a] p :: Ptr Int32 <- newPtr externProc "ptr_proc1" [ptrArg p] externProc "ptr_proc2" [addr $ ptrArg p] externProc "ptr_proc3" [deref $ ptrArg p] o <- newObject "int" False externProc "obj_proc1" [objArg o] externProc "obj_proc2" [addr $ objArg o] op <- newObject "int" True externProc "obj_proc3" [objArg op] externProc "obj_proc4" [addr $ objArg op] externProc "obj_proc5" [deref $ objArg op] let s = "apa" externProc "str_proc1" [strArg s] externProc "str_proc2" [deref $ strArg s] return () ---------------------------------------- -- It would be nice to be able to run these tests using Tests.Tasty.HUnit, but -- I wasn't able to make that work, probably due to the use of `fakeIO` in the -- tests. First, Tasty wasn't able to silence the output of the tests, and -- secondly, the tests would always fail when running a second time. testAll = do tag "testTypes" >> compareCompiled testTypes (runIO testTypes) "0\n" tag "testCExp" >> compareCompiledM testCExp (runIO testCExp) "44\n" tag "testRef" >> compareCompiled testRef (runIO testRef) "" tag "testArr1" >> compareCompiled testArr1 (runIO testArr1) "" tag "testArr2" >> compareCompiled testArr2 (runIO testArr2) "20\n" tag "testArr3" >> compareCompiled testArr3 (runIO testArr3) "" tag "testArr4" >> compareCompiled testArr4 (runIO testArr4) "" tag "testArr5" >> compareCompiled testArr5 (runIO testArr5) "" tag "testArr6" >> compareCompiled testArr6 (runIO testArr6) "" tag "testArr7" >> compareCompiled testArr7 (runIO testArr6) "" tag "testArr7" >> compareCompiled testArr7 (runIO testArr7) "" tag "testSwap1" >> compareCompiled testSwap1 (runIO testSwap1) "" tag "testSwap2" >> compareCompiled testSwap2 (runIO testSwap2) "45\n" tag "testIf1" >> compareCompiled testIf1 (runIO testIf1) "12\n" tag "testIf2" >> compareCompiled testIf2 (runIO testIf2) "12\n" tag "testFor1" >> compareCompiled testFor1 (runIO testFor1) "" tag "testFor2" >> compareCompiled testFor2 (runIO testFor2) "" tag "testFor3" >> compareCompiled testFor3 (runIO testFor3) "" tag "testAssert" >> compareCompiled testAssert (runIO testAssert) "45" tag "testPtr" >> compareCompiled testPtr (putStrLn "34" >> putStrLn "sum: 280") "" tag "testArgs" >> compareCompiled testArgs (putStrLn "55 66 234 234 66 55 66") "" tag "testExternArgs" >> compileAndCheck testExternArgs where tag str = putStrLn $ "---------------- tests/Imperative.hs/" ++ str ++ "\n" compareCompiledM = compareCompiled' defaultExtCompilerOpts {externalFlagsPost = ["-lm"]}