From e699643f3b036dc39643a0ee322b2ee256fa23f5 Mon Sep 17 00:00:00 2001
From: Ben Gamari <ben@smart-cactus.org>
Date: Wed, 22 Jun 2022 14:19:37 -0400
Subject: [PATCH] CCall: Extend to test signed arguments and results

Closes #3.
---
 src/CCall.hs | 60 +++++++++++++++++++++++++++++++---------------------
 1 file changed, 36 insertions(+), 24 deletions(-)

diff --git a/src/CCall.hs b/src/CCall.hs
index 8632bde..53880e6 100644
--- a/src/CCall.hs
+++ b/src/CCall.hs
@@ -4,7 +4,6 @@ module CCall
     , testCCall
     ) where
 
-import Numeric.Natural
 import System.FilePath
 import System.IO.Temp
 import Test.QuickCheck
@@ -17,7 +16,8 @@ import Number
 
 data CCallDesc
     = CCallDesc { callRet :: SomeNumber
-                , callArgs :: [SomeNumber]
+                , callRetSignedness :: Signedness
+                , callArgs :: [(Signedness, SomeNumber)]
                 }
     deriving (Show)
 
@@ -30,9 +30,10 @@ mAX_ARGS = 32
 instance Arbitrary CCallDesc where
     arbitrary = do
         ret <- arbitrary
+        ret_signedness <- arbitrary
         n <- chooseInt (0, mAX_ARGS)
         args <- vectorOf n arbitrary
-        return $ CCallDesc ret args
+        return $ CCallDesc ret ret_signedness args
 
 testCCall
     :: Compiler
@@ -44,11 +45,11 @@ testCCall comp c =
         writeFile (tmpDir </> "test.cmm") (cCallCmm c)
         compile comp tmpDir ["test_c.c", "test.cmm"] soName ["-shared", "-dynamic"]
         out <- runIt comp (tmpDir </> soName)
-        let saw :: [Natural]
+        let saw :: [Integer]
             saw = map read (lines out)
-            expected :: [Natural]
-            expected = map (\(SomeNumber e) -> toUnsigned e) (callArgs c) ++ [ret]
-            ret = case callRet c of SomeNumber n -> toUnsigned n
+            expected :: [Integer]
+            expected = map (\(s, SomeNumber e) -> asInteger s e) (callArgs c) ++ [ret]
+            ret = case callRet c of SomeNumber n -> asInteger (callRetSignedness c) n
         return $ saw === expected
 
   where
@@ -65,11 +66,14 @@ cStub c
     ]
   where
     argBndrs = [ "arg"++show i | (i,_) <- zip [0::Int ..] (callArgs c) ]
-    argWidths = [ knownWidth @w | SomeNumber (_ :: Number w) <- callArgs c ]
+    argTypes =
+      [ (signedness, knownWidth @w)
+      | (signedness, SomeNumber (_ :: Number w)) <- callArgs c
+      ]
 
     funcDef = unlines $
-      [ cType (retWidth c) <> " test_c(" <> argList <> ") {" ] ++
-      zipWith printArg argWidths argBndrs ++
+      [ cType Unsigned (retWidth c) <> " test_c(" <> argList <> ") {" ] ++
+      zipWith printArg argTypes argBndrs ++
       [ "  fflush(stdout);"
       , "  return " ++ show (someNumberToUnsigned $ callRet c) ++ "ULL;"
       , "}"
@@ -77,39 +81,47 @@ cStub c
 
     argList =
         commaList
-        [ unwords [cType w, bndr]
-        | (w, bndr) <- zip argWidths argBndrs
+        [ unwords [ty, bndr]
+        | (ty, bndr) <- zip (map (uncurry cType) argTypes) argBndrs
         ]
-    printArg w bndr =
-        "  printf(" ++ quoted (formatStr w ++ "\\n") ++ ", " ++ bndr ++ ");"
+    printArg ty bndr =
+        "  printf(" ++ quoted (formatStr ty ++ "\\n") ++ ", " ++ bndr ++ ");"
 
 quoted :: String -> String
 quoted s = "\"" ++ s ++ "\""
 
-formatStr :: Width -> String
-formatStr w =
+formatStr :: (Signedness, Width) -> String
+formatStr (_signedness, w) =
     "0x%" ++ quoted ("PRIx"++show n)
   where
     n = widthBits w
 
-cType :: Width -> String
-cType W8  = "uint8_t"
-cType W16 = "uint16_t"
-cType W32 = "uint32_t"
-cType W64 = "uint64_t"
+cType :: Signedness -> Width -> String
+cType signedness width  = prefix ++ "int" ++ show n ++ "_t"
+  where
+    n = widthBits width
+    prefix = case signedness of
+      Signed   -> ""
+      Unsigned -> "u"
 
 cCallCmm :: CCallDesc -> String
 cCallCmm c = unlines
     [ "test("++cmmWordType ++" buffer) {"
     , "  "++cmmType (retWidth c)++" ret;"
-    , "  (ret) = foreign \"C\" test_c(" ++ argList ++ ");"
+    , "  (" ++ retHint ++ "ret) = foreign \"C\" test_c(" ++ argList ++ ");"
     , "  return ("++widenOp++"(ret));"
     , "}"
     ]
   where
+    retHint = case callRetSignedness c of
+                Signed   -> "\"signed\" "
+                Unsigned -> ""
     widenOp = "%zx" ++ show (widthBits wordSize)
     argList =
         commaList
-        [ exprToCmm $ ELit e
-        | SomeNumber e <- callArgs c
+        [ exprToCmm (ELit e) ++ hint
+        | (signedness, SomeNumber e) <- callArgs c
+        , let hint = case signedness of
+                       Signed -> " \"signed\""
+                       Unsigned -> ""
         ]
-- 
GitLab