-- {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleInstances #-} module C where import Control.Monad.State.Strict import Data.Data import Data.Either import Data.Typeable import Data.String import Data.ByteString.Char8 (ByteString,pack,unpack) import qualified Data.ByteString.Char8 as ByteString import Network.Mime (defaultMimeLookup) import System.Directory import System.FilePath import System.IO import Text.Printf import Types import JS -- toFile :: MonadIO m => FilePath -> Writer ByteString a -> m () -- toFile f wr = liftIO $ do -- createDirectoryIfMissing True (takeDirectory f) -- ByteString.writeFile f $ execWriter $ wr toFile :: MonadIO m => FilePath -> StateT Handle IO () -> m () toFile f m = liftIO $ do createDirectoryIfMissing True (takeDirectory f) withFile f WriteMode (evalStateT m) class LineLike x where line :: x -> StateT Handle IO () line_ putter s = get >>= \h -> liftIO $ putter h s instance LineLike ByteString where line = line_ ByteString.hPutStrLn instance LineLike [Char] where line = line . pack instance LineLike [[Char]] where line s = forM_ s (\s -> line_ ByteString.hPutStr (pack s)) >> line "" mk_c :: Args -> ByteString -> IO () mk_c a d = toFile (out_c a) $ do line $ "/* http://stupefydeveloper.blogspot.ru/2008/08/cc-embed-binary-data-into-elf.html */" line $ "#include " line $ "#include " line $ "#include \"" ++ (takeFileName (out_h a)) ++ "\"" line $ "" line $ "#define BLOBSZ " ++ (printf "%d" (ByteString.length d)) line $ "static char blob[BLOBSZ];" line $ "" line $ [ "uw_Basis_blob ", cblobfun a , " (uw_context ctx, uw_unit unit)" ] line $ "{" line $ " uw_Basis_blob uwblob;" line $ " uwblob.data = &blob[0];" line $ " uwblob.size = BLOBSZ;" line $ " return uwblob;" line $ "}" line $ "" line $ [ "uw_Basis_string " , ctextfun a , " (uw_context ctx, uw_unit unit) {" ] line $ " char* data = &blob[0];" line $ " size_t size = sizeof(blob);" line $ " char * c = uw_malloc(ctx, size+1);" line $ " char * write = c;" line $ " int i;" line $ " for (i = 0; i < size; i++) {" line $ " *write = data[i];" line $ " if (*write == '\\0')" line $ " *write = '\\n';" line $ " *write++;" line $ " }" line $ " *write=0;" line $ " return c;" line $ " }" line $ "" line $ "static char blob[BLOBSZ] = {" h <- get liftIO $ do forM_ (unpack d) $ \c -> do hPutStr h (printf "0x%02X ," c) -- liftIO $ ByteString.foldl' (\act c -> act >> hPutStr h (printf "0x%02X ," c)) (return ()) d line $ "};" line $ "" mk_h :: Args -> IO () mk_h a = toFile (out_h a) $ do line $ "#pragma once" line $ "#include " line $ [ "uw_Basis_blob ", cblobfun a , " (uw_context ctx, uw_unit unit);" ] line $ [ "uw_Basis_string ", ctextfun a, " (uw_context ctx, uw_unit unit);" ] mk_urs :: Args -> IO () mk_urs a = toFile (out_urs a) $ do line $ [ "val ", urblobfun, " : unit -> transaction blob" ] line $ [ "val ", urtextfun, " : unit -> transaction string" ] guessMime inf = fixup $ unpack (defaultMimeLookup (fromString inf)) where fixup "application/javascript" = "text/javascript" fixup m = m mk_wrap :: Args -> [Url] -> Bool -> IO () mk_wrap a us open_js_ffi = do toFile (out_wrapper a) $ do let mm = guessMime (inp a) line $ "open " ++ (uwModName (out_urs a)) line $ "fun content {} = b <- "++ urblobfun ++ " () ; returnBlob b (blessMime \"" ++ mm ++ "\")" line $ "val propagated_urls : list url = " forM_ us $ \u -> do line $ " " ++ u ++ ".url ::" line $ " []" when (open_js_ffi) $ do line $ "open " ++ (uwModName (out_ffi_js a)) line $ "val url = url(content {})" line $ "val geturl = url" liftIO $ printf "safeGet %s/content\n" (uwModName (out_wrapper a)) liftIO $ printf "allow mime %s\n" mm mk_js_wrap :: Args -> ([JSType],[JSFunc]) -> IO () mk_js_wrap a (jt,jf) = do let m = uwModName (out_ffi_js a) toFile (out_ffi_js a) $ do forM_ jt $ \decl -> line (urtdecl decl) forM_ jf $ \decl -> do line (urdecl decl) liftIO $ printf "jsFunc %s.%s = %s\n" m (urname decl) (jsname decl) liftIO $ printf "clientOnly %s.%s\n" m (urname decl) -- mk_js_lib :: Args -> ([JSType],[JSFunc]) -> IO () -- mk_js_lib a (jt,jf) = do -- toFile (out_ffi_js_lib a) $ do -- let m = uwModName (out_ffi_js a) -- line $ "ffi " ++ m -- forM_ jf $ \decl -> do