Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Building Haddock documentation without compiling the source

I'm working on a Haskell library that contains parts that target WebAssembly (WASM) using Asterius. These parts can't be compiled with the normal ghc and for that reason we have flags that exclude/include the WASM parts.

Trying to build the documentation with Asterius' ahc-cabal new-haddock fails. It seems to revert to the normal ghc for the Haddock command.

My question is: Can I build the Haddock documentation without compiling the source it describes?


Excerpts of my file that might be relevante:

Section of my cabal file:

flag wasm
  description:         Eanbles builds targeting WASM.
  default:             False
  manual:              True

library
  exposed-modules:     Boardgame
  build-depends:       base >= 4.12 && < 5.0
  if flag(wasm)
    exposed-modules:   Boardgame.Web
    build-depends:
        aeson >= 1.4 && < 1.6
      , asterius-prelude == 0.0.1
      , scientific >= 0.3 && < 0.4
    CPP-options:       "-DWASM"

Section of Boardgame.hs:

#ifdef WASM
import Data.Aeson (ToJSON(toJSON), Value(Number, Null))
import Data.Scientific (fromFloatDigits)
#endif

-- | Represents one of the two players.
data Player = Player1 | Player2
  deriving (Show, Eq)

#ifdef WASM
instance ToJSON Player where
  toJSON = Number . fromFloatDigits . fromIntegral . playerToInt
#endif

Section of Boardgame/Web.hs:

module Boardgame.Web (
    addWebGame
) where

foreign import javascript "wrapper" jsMakeCallback :: IO () -> IO JSVal
foreign import javascript "boardgame.games[$1] = $2" jsSetGame :: JSVal -> JSVal -> IO ()

-- | Adds a named game to the list of games accessible from JavaScript.
addWebGame :: (ToJSON a, ToJSON c, FromJSON c, PositionalGame a c) => String -> a -> IO ()
addWebGame name startState = do
  callback <- jsMakeCallback $ playWeb startState
  jsSetGame (jsonToJSVal name) callback

My main file (Boardgame.hs) contains code "hidden" behind the WASM flag but no of code has any documentation. Boardgame/Web.hs is only included when the WASM flag is specified and has some functions with documentation.

I want to build the documentation for all documented functions in both Boardgame.hs and Boardgame/Web.hs.

like image 783
Netråm Avatar asked Nov 07 '22 02:11

Netråm


1 Answers

Instead of excluding your module Boardgame/Web.hs, which contains the imports that GHC can't process, entirely when the WASM flag is set, you could use CPP in Boardgame/Web.hs to conditionally set all non-GHC-compatible symbols to undefined.

The way I would do it is to move all type signatures to the top of the module, and make two sets of definitions, like so:

module Boardgame.Web (
    addWebGame
) where

addWebGame :: (ToJSON a, ToJSON c, FromJSON c, PositionalGame a c) => String -> a -> IO ()
-- other signatures...

#ifdef WASM
foreign import javascript "wrapper" jsMakeCallback :: IO () -> IO JSVal
foreign import javascript "boardgame.games[$1] = $2" jsSetGame :: JSVal -> JSVal -> IO ()

addWebGame name startState = do
  callback <- jsMakeCallback $ playWeb startState
  jsSetGame (jsonToJSVal name) callback

-- other definitions...

#else

addWebGame = undefined

#endif

Boardgame.Web should then be imported unconditionally.

This should build with GHC. It will obviously error without doing anything useful if run, but it's enough to let cabal/haddock extract the documentation.

The downside is changing the way you structure your code.

I'm sure this can be automated with something like an awk script, but it's beyond me.

Alternatively, if it's just the FFI declarations that are the problem, you could do this much simpler (and more automably):

module Boardgame.Web (
    addWebGame
) where

#ifdef WASM
foreign import javascript "wrapper" jsMakeCallback :: IO () -> IO JSVal
foreign import javascript "boardgame.games[$1] = $2" jsSetGame :: JSVal -> JSVal -> IO ()

#else
jsMakeCallback = undefined
jsSetGame = undefined
#endif

-- addWebGame and others unmodified.

To get you started with automating, a command like cat Boardgame/Web.hs | sed "s/foreign import javascript \"[^\"]*\" \([^ ]*\).*/\1 = undefined/" will extract a list of javascript imports and convert them into undefined assignments.

Happy Haskelling!

like image 91
Ari Fordsham Avatar answered Nov 12 '22 19:11

Ari Fordsham