Skip to content

Commit d215842

Browse files
committed
State of roundtrip testing
1 parent 907804d commit d215842

File tree

9 files changed

+2649
-2
lines changed

9 files changed

+2649
-2
lines changed

configure.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -271,4 +271,4 @@ rm -fr dist*
271271
# cabal configure -fdev --with-compiler=/opt/ghc/9.13.20250316/bin/ghc --allow-newer
272272
# cabal configure -fdev -froundtrip --enable-tests --with-compiler=/opt/ghc/9.13.20250316/bin/ghc --allow-newer
273273
# cabal configure -fdev -froundtrip --enable-tests --with-compiler=/opt/ghc/9.13.20250331/bin/ghc --allow-newer
274-
cabal configure -fdev -froundtrip --enable-tests --with-compiler=/opt/ghc/9.13.20250427/bin/ghc --allow-newer
274+
cabal configure -fdev -froundtrip --enable-tests --with-compiler=/opt/ghc/9.13.20250506/bin/ghc --allow-newer

roundtrip-config/knownfailures.txt

Lines changed: 1224 additions & 1 deletion
Large diffs are not rendered by default.

tests/examples/ghc-cpp/CAS.hs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
-- from ./hackage-roundtrip-work/IORefCAS-0.2.0.1/Data/CAS.hs
2+
{-# LANGUAGE CPP
3+
#-}
4+
5+
-- | Atomic compare and swap for IORefs and STRefs.
6+
module Data.CAS
7+
(
8+
-- Not currently provided by Fake.hs:
9+
-- casSTRef,
10+
casIORef, ptrEq,
11+
atomicModifyIORefCAS, atomicModifyIORefCAS_,
12+
13+
-- * Generic interface: for interoperation with `Fake` and `Foreign` alternative libraries.
14+
CASRef)
15+
where
16+
17+
#if __GLASGOW_HASKELL__ <= 702 /* Fix to casMutVar introduced 2011.12.09 */
18+
#warning "casMutVar is not included or is bugged in your GHC, falling back to Fake version."
19+
import Data.CAS.Internal.Fake
20+
#else
21+
import Data.CAS.Internal.Native
22+
#endif
23+

tests/examples/ghc-cpp/FFI.hs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
-- originally ./hackage-roundtrip-work/Scurry-0.0.3/src/Network/Util.hs
2+
{-# OPTIONS -XForeignFunctionInterface #-}
3+
{-# LANGUAGE CPP #-}
4+
5+
module Network.Util (
6+
htonl,
7+
htons,
8+
ntohl,
9+
ntohs,
10+
) where
11+
12+
import Data.Word
13+
14+
foreign import CALLCONV unsafe "htonl" htonl :: Word32 -> Word32
15+
foreign import CALLCONV unsafe "htons" htons :: Word16 -> Word16
16+
foreign import CALLCONV unsafe "ntohl" ntohl :: Word32 -> Word32
17+
foreign import CALLCONV unsafe "ntohs" ntohs :: Word16 -> Word16
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
-- From ./hackage-roundtrip-work/hopenssl-2.2.5/src/OpenSSL/EVP/Digest/Initialization.hs
2+
{-# LANGUAGE CPP #-}
3+
{-# LANGUAGE ForeignFunctionInterface #-}
4+
5+
{- |
6+
Maintainer: simons@cryp.to
7+
Stability: provisional
8+
Portability: portable
9+
10+
Low-level bindings to OpenSSL's EVP interface. Most users do not need this
11+
code. Check out "OpenSSL.Digest" for a more comfortable interface.
12+
-}
13+
14+
module OpenSSL.EVP.Digest.Initialization ( initializeEVPDigests ) where
15+
16+
import Control.Concurrent.MVar
17+
import Control.Monad
18+
import System.IO.Unsafe as IO
19+
20+
#include "openssl/opensslv.h"
21+
22+
-- | Initialize the OpenSSL EVP engine and register all known digest types in
23+
-- the internal data structures. This function must be called before any of the
24+
-- message digest functions can succeed. This is generally handled
25+
-- transparently by the Haskell implementation and users do not need to worry
26+
-- about this.
27+
28+
initializeEVPDigests :: IO ()
29+
initializeEVPDigests =
30+
#if OPENSSL_VERSION_NUMBER >= 0x1010000f
31+
return ()
32+
#else
33+
modifyMVar_ isDigestEngineInitialized $ \isInitialized ->
34+
unless isInitialized _addAllDigests >> return True
35+
36+
{-# NOINLINE isDigestEngineInitialized #-}
37+
isDigestEngineInitialized :: MVar Bool
38+
isDigestEngineInitialized = IO.unsafePerformIO $ newMVar False
39+
40+
foreign import ccall unsafe "openssl/evp.h OpenSSL_add_all_digests" _addAllDigests :: IO ()
41+
42+
#endif
43+

tests/examples/ghc-cpp/Lexer.hs

Lines changed: 618 additions & 0 deletions
Large diffs are not rendered by default.

tests/examples/ghc-cpp/Promise.hs

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
-- From ./hackage-roundtrip-work/ghcjs-promise-0.1.0.3/src/Data/JSVal/Promise.hs
2+
{-# LANGUAGE JavaScriptFFI
3+
, OverloadedStrings
4+
#-}
5+
6+
{-|
7+
8+
Module : Data.JSVal.Promise
9+
Copyright : (c) Alejandro Durán Pallarés, 2016
10+
License : BSD3
11+
Maintainer : vwwv@correo.ugr.es
12+
Stability : experimental
13+
14+
15+
Data.JSVal.Promise defines `Promise`, a direct bind to javascript promise objects.
16+
17+
- You can import/export them from javascript code using its `FromJSVal` and `ToJSVal` instances.
18+
19+
- You can extract its value, blocking till computation has finished, using `await`. (you can safely call
20+
it several time from different threads, the associated computation will run once, and then memorized)
21+
22+
- You can create new promise (to possible use js side) containing arbitrary haskell code using `promise`.
23+
24+
For some usage example, checkout this [blog entry](http://the.spaghetticodeball.xyz/haskell/javascript/2016/10/10/new-library-ghcjs-promise.html).
25+
26+
-}
27+
28+
29+
module Data.JSVal.Promise( Promise()
30+
, await
31+
, promise
32+
) where
33+
34+
import GHCJS.Marshal
35+
import GHCJS.Types
36+
import GHCJS.Foreign
37+
import Control.Exception
38+
import Control.Concurrent
39+
40+
41+
newtype Promise = Promise {fromPromise :: JSVal}
42+
43+
instance FromJSVal Promise where
44+
fromJSVal x = do is_promise <- js_check_if_promise x
45+
if is_promise
46+
then return . Just $ Promise x
47+
else return Nothing
48+
49+
instance ToJSVal Promise where
50+
toJSVal = return . fromPromise
51+
52+
-- | If the promise is return through "then", it will return `Right`;
53+
-- if it return through "catch", then it will return `Left`
54+
await :: Promise -> IO (Either JSVal JSVal)
55+
await (Promise jsval) = do result <- js_await jsval
56+
x <- js_attribute "result" result
57+
ok <- isTruthy <$> js_attribute "ok" result
58+
if ok
59+
then return (Right x)
60+
else return (Left x)
61+
62+
-- | A `Right` value will be sent as a normal value through "then", a left
63+
-- value will be sent through "catch" (by javascript convention, representing
64+
-- an exception).
65+
--
66+
-- The block will start executing immediately, no mater if there's something waiting
67+
-- for it or not.
68+
--
69+
-- If the execution block launches an exception, then the promise will be receive
70+
-- as "reject", the javascript value "new Error('Haskell side error')"
71+
promise :: IO (Either JSVal JSVal) -> IO Promise
72+
promise action = do ref <- js_book_promise
73+
promise <- js_set_promise ref
74+
myid <- myThreadId
75+
forkIO $ do val_ <- try action
76+
case val_ of
77+
78+
Right (Right x) -> js_do_resolve ref x
79+
80+
Right (Left x) -> js_do_reject ref x
81+
82+
Left exc -> do throwTo myid (exc::SomeException)
83+
js_do_reject ref =<< create_error
84+
return $ Promise promise
85+
-----------------------------------------------------------------------
86+
-----------------------------------------------------------------------
87+
88+
89+
-- This works because the [algorithm](http://www.ecma-international.org/ecma-262/6.0/#sec-promise.resolve)
90+
-- explicitly demands that Promise.resolve must return the exact object passed in if and only if
91+
-- it is a promise by the definition of the spec.
92+
-- (from stackoverflow http://stackoverflow.com/questions/27746304/how-do-i-tell-if-an-object-is-a-promise)
93+
foreign import javascript safe
94+
"Promise.resolve($1) == $1"
95+
js_check_if_promise :: JSVal -> IO Bool
96+
97+
foreign import javascript safe
98+
"$2[$1]"
99+
js_attribute :: JSString -> JSVal -> IO JSVal
100+
101+
foreign import javascript safe
102+
"new Error('Haskell side error')"
103+
create_error :: IO JSVal
104+
105+
106+
foreign import javascript safe
107+
"__js_book_promise()"
108+
js_book_promise :: IO JSVal
109+
110+
foreign import javascript safe
111+
"__js_set_promise($1)"
112+
js_set_promise :: JSVal -> IO JSVal
113+
114+
foreign import javascript safe
115+
"__js_do_reject($1,$2);"
116+
js_do_reject :: JSVal -> JSVal -> IO ()
117+
118+
foreign import javascript safe
119+
"__js_do_resolve($1, $2);"
120+
js_do_resolve :: JSVal -> JSVal -> IO ()
121+
122+
foreign import javascript interruptible
123+
"__js_await($1,$c);"
124+
js_await :: JSVal -> IO JSVal
125+

tests/examples/ghc-cpp/Regions.hs

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
-- ./hackage-roundtrip-work/inline-r-1.0.1/tests/Test/Regions.hs
2+
{-# LANGUAGE DataKinds #-}
3+
{-# LANGUAGE QuasiQuotes #-}
4+
{-# LANGUAGE CPP #-}
5+
{-# LANGUAGE ForeignFunctionInterface #-}
6+
7+
module Test.Regions
8+
( tests )
9+
where
10+
11+
import H.Prelude
12+
import qualified Foreign.R as R
13+
14+
import Test.Tasty hiding (defaultMain)
15+
import Test.Tasty.HUnit
16+
import Foreign
17+
18+
19+
#include <Rversion.h>
20+
21+
#if defined(R_VERSION) && R_VERSION >= R_Version(3, 1, 0)
22+
foreign import ccall "&R_PPStackTop" ppStackTop :: Ptr Int
23+
#endif
24+
25+
assertBalancedStack :: IO () -> IO ()
26+
#if defined(R_VERSION) && R_VERSION >= R_Version(3, 1, 0)
27+
assertBalancedStack m = do
28+
i <- peek ppStackTop
29+
m
30+
j <- peek ppStackTop
31+
assertEqual "protection stack should be balanced" i j
32+
#else
33+
assertBalancedStack m = do
34+
putStrLn "Warning: Cannot check stack balance on R < 3.1. Disabling check."
35+
m
36+
#endif
37+
38+
-- XXX these tests are only effective when using a "hardened" version of
39+
-- R compiled with --enable-strict-barrier enabled, and with the R_GCTORTURE
40+
-- environment variable set.
41+
42+
tests :: TestTree
43+
tests = testGroup "regions"
44+
[ testCase "qq-object-live-inside-extend" $
45+
assertBalancedStack $
46+
runRegion $ do
47+
R.SomeSEXP x <- [r| 1 |]
48+
_ <- [r| gc() |]
49+
io $ assertEqual "value is protected" R.Real (R.typeOf x)
50+
, testCase "mksexp-object-live-inside-extend" $
51+
assertBalancedStack $
52+
runRegion $ do
53+
x <- mkSEXP (1::Int32)
54+
_ <- [r| gc() |]
55+
io $ assertEqual "value is protected" R.Int (R.typeOf x)
56+
, testCase "runRegion-no-leaked-thunks" $
57+
((8 @=?) =<<) $ do
58+
z <- runRegion $ fmap dynSEXP [r| 5+3 |]
59+
_ <- runRegion $ [r| gc() |] >> return ()
60+
return (z::Int32)
61+
]
62+

0 commit comments

Comments
 (0)