-- {-# LANGUAGE DeriveGeneric #-}
-- {-# OPTIONS_GHC -O2 #-}

module UHC.Light.Compiler.CoreRun.Run.Val.Prim
( rvalPrim )
where
import UHC.Light.Compiler.CoreRun.Prim
import UHC.Light.Compiler.CoreRun.Run.Val
import UHC.Light.Compiler.CoreRun.Run
import UHC.Light.Compiler.CoreRun
import UHC.Util.Pretty
import qualified Data.Vector as V
import qualified Data.Vector.Mutable as MV
import qualified Data.ByteString.Char8 as BSC8
import Data.Bits
import Data.Maybe
import GHC.Generics

{-# LINE 40 "src/ehc/CoreRun/Run/Val/Prim.chs" #-}
-- | Apply primitive to arguments
rvalPrim :: (RunSem RValCxt RValEnv RVal m a) => RunPrim -> RValV -> RValT m a
rvalPrim pr as = do
    as' <- forM (V.toList as) $ \a -> rsemDeref a >>= rsemPop
    -- let as' = V.toList as
    -- rsemTr $ "Prim:" >#< show pr >|< ppParensCommas as'
    case (pr, as') of
      -- Unsafe stuff
      (RP_primUnsafeId, [x]) -> rsemPush x

      -- Char
      (RP_primEqChar		, [RVal_Char i1, RVal_Char i2]	) -> hsUnmarshall $ i1 == i2
      (RP_primCmpChar		, [RVal_Char i1, RVal_Char i2]	) -> hsUnmarshall $ i1 `compare` i2

      (RP_primCharToInt  	, [RVal_Char x]					) -> rsemPush $ RVal_Int $ fromEnum x
      (RP_primIntToChar  	, [RVal_Int x]					) -> rsemPush $ RVal_Char $ toEnum x

      -- Int
      (RP_primAddInt		, [RVal_Int i1, RVal_Int i2]) -> rsemPush $ RVal_Int $ i1 + i2
      (RP_primSubInt		, [RVal_Int i1, RVal_Int i2]) -> rsemPush $ RVal_Int $ i1 - i2
      (RP_primMulInt		, [RVal_Int i1, RVal_Int i2]) -> rsemPush $ RVal_Int $ i1 * i2
      (RP_primDivInt		, [RVal_Int i1, RVal_Int i2]) -> rsemPush $ RVal_Int $ i1 `div` i2
      (RP_primQuotInt		, [RVal_Int i1, RVal_Int i2]) -> rsemPush $ RVal_Int $ i1 `quot` i2
      (RP_primRemInt		, [RVal_Int i1, RVal_Int i2]) -> rsemPush $ RVal_Int $ i1 `rem` i2
      (RP_primModInt		, [RVal_Int i1, RVal_Int i2]) -> rsemPush $ RVal_Int $ i1 `mod` i2
      (RP_primNegInt		, [RVal_Int i1]				) -> rsemPush $ RVal_Int (-i1)

      (RP_primDivModInt		, [RVal_Int i1, RVal_Int i2]) -> hsUnmarshall $ i1 `divMod` i2
      (RP_primQuotRemInt	, [RVal_Int i1, RVal_Int i2]) -> hsUnmarshall $ i1 `quotRem` i2

      (RP_primMinInt		, []						) -> rsemPush $ RVal_Int minBound
      (RP_primMaxInt		, []						) -> rsemPush $ RVal_Int maxBound

      (RP_primEqInt			, [RVal_Int i1, RVal_Int i2]) -> hsUnmarshall $ i1 == i2
      (RP_primNeInt			, [RVal_Int i1, RVal_Int i2]) -> hsUnmarshall $ i1 /= i2

      (RP_primCmpInt		, [RVal_Int i1, RVal_Int i2]) -> hsUnmarshall $ i1 `compare` i2
      (RP_primLeInt			, [RVal_Int i1, RVal_Int i2]) -> hsUnmarshall $ i1 <= i2
      (RP_primLtInt			, [RVal_Int i1, RVal_Int i2]) -> hsUnmarshall $ i1 <  i2
      (RP_primGeInt			, [RVal_Int i1, RVal_Int i2]) -> hsUnmarshall $ i1 >= i2
      (RP_primGtInt			, [RVal_Int i1, RVal_Int i2]) -> hsUnmarshall $ i1 >  i2

      (RP_primAndInt		, [RVal_Int i1, RVal_Int i2]) -> rsemPush $ RVal_Int $ i1 .&. i2
      (RP_primOrInt			, [RVal_Int i1, RVal_Int i2]) -> rsemPush $ RVal_Int $ i1 .|. i2
      (RP_primXorInt		, [RVal_Int i1, RVal_Int i2]) -> rsemPush $ RVal_Int $ i1 `xor` i2
      (RP_primComplementInt	, [RVal_Int i1]				) -> rsemPush $ RVal_Int $ complement i1
      (RP_primShiftLeftInt	, [RVal_Int i1, RVal_Int i2]) -> rsemPush $ RVal_Int $ i1 `shiftL` i2
      (RP_primShiftRightInt	, [RVal_Int i1, RVal_Int i2]) -> rsemPush $ RVal_Int $ i1 `shiftR` i2
      (RP_primRotateLeftInt	, [RVal_Int i1, RVal_Int i2]) -> rsemPush $ RVal_Int $ i1 `rotateL` i2
      (RP_primRotateRightInt, [RVal_Int i1, RVal_Int i2]) -> rsemPush $ RVal_Int $ i1 `rotateR` i2
      {-
      (RP_primBitSize		, [RVal_Int i1]				) -> rsemPush $ RVal_Int $ bitSize i1 -- fromJust $ bitSizeMaybe i1
      -}
      (RP_primBitSize		, [RVal_Int i1]				) -> rsemPush $ RVal_Int $ fromJust $ bitSizeMaybe i1
      (RP_primBitSizeMaybe	, [RVal_Int i1]				) -> hsUnmarshall $ bitSizeMaybe i1
      (RP_primPopCount		, [RVal_Int i1]				) -> rsemPush $ RVal_Int $ popCount i1
      (RP_primBit			, [RVal_Int i1]				) -> rsemPush $ RVal_Int $ bit i1

      (RP_primIntToInteger  , [RVal_Int x]				) -> rsemPush $ RVal_Integer $ fromIntegral x
      (RP_primIntegerToInt  , [RVal_Integer x]			) -> rsemPush $ RVal_Int $ fromIntegral x

      -- Integer
      (RP_primAddInteger		, [RVal_Integer i1, RVal_Integer i2]) -> rsemPush $ RVal_Integer $ i1 + i2
      (RP_primSubInteger		, [RVal_Integer i1, RVal_Integer i2]) -> rsemPush $ RVal_Integer $ i1 - i2
      (RP_primMulInteger		, [RVal_Integer i1, RVal_Integer i2]) -> rsemPush $ RVal_Integer $ i1 * i2
      (RP_primDivInteger		, [RVal_Integer i1, RVal_Integer i2]) -> rsemPush $ RVal_Integer $ i1 `div` i2
      (RP_primQuotInteger		, [RVal_Integer i1, RVal_Integer i2]) -> rsemPush $ RVal_Integer $ i1 `quot` i2
      (RP_primRemInteger		, [RVal_Integer i1, RVal_Integer i2]) -> rsemPush $ RVal_Integer $ i1 `rem` i2
      (RP_primModInteger		, [RVal_Integer i1, RVal_Integer i2]) -> rsemPush $ RVal_Integer $ i1 `mod` i2
      (RP_primNegInteger		, [RVal_Integer i1]					) -> rsemPush $ RVal_Integer (-i1)

      (RP_primDivModInteger		, [RVal_Integer i1, RVal_Integer i2]) -> hsUnmarshall $ i1 `divMod` i2
      (RP_primQuotRemInteger	, [RVal_Integer i1, RVal_Integer i2]) -> hsUnmarshall $ i1 `quotRem` i2

      (RP_primEqInteger			, [RVal_Integer i1, RVal_Integer i2]) -> hsUnmarshall $ i1 == i2
      (RP_primNeInteger			, [RVal_Integer i1, RVal_Integer i2]) -> hsUnmarshall $ i1 /= i2

      (RP_primCmpInteger		, [RVal_Integer i1, RVal_Integer i2]) -> hsUnmarshall $ i1 `compare` i2
      (RP_primLeInteger			, [RVal_Integer i1, RVal_Integer i2]) -> hsUnmarshall $ i1 <= i2
      (RP_primLtInteger			, [RVal_Integer i1, RVal_Integer i2]) -> hsUnmarshall $ i1 <  i2
      (RP_primGeInteger			, [RVal_Integer i1, RVal_Integer i2]) -> hsUnmarshall $ i1 >= i2
      (RP_primGtInteger			, [RVal_Integer i1, RVal_Integer i2]) -> hsUnmarshall $ i1 >  i2

      -- Exception handling
      (RP_primCatchException, [x, hdl]) -> rsemEvl x -- err $ "Not impl: RP_primCatchException" -- TBD

      -- Base
      (RP_primPackedStringToInteger, [RVal_PackedString x]) -> rsemPush $ RVal_Integer $ read $ BSC8.unpack x
      (RP_primPackedStringNull, [RVal_PackedString x]) -> hsUnmarshall $ BSC8.null x
      (RP_primPackedStringHead, [RVal_PackedString x]) -> rsemPush $ RVal_Char $ BSC8.head x
      (RP_primPackedStringTail, [RVal_PackedString x]) -> rsemPush $ RVal_PackedString $ BSC8.tail x
      (RP_primShowInteger, [RVal_Integer x]) -> hsUnmarshall $ show x

      -- Prims: conversion
      (RP_primIntegerToInt32, [RVal_Integer x]) -> rsemPush $ RVal_Int32 $ fromIntegral x

      -- IO
{-
		--- * The IO monad

-}

		--- * Files and handles

	  -- FilePath                  -- :: String

	  -- Handle             -- abstract, instance of: Eq, Show.

		--- ** Standard handles

		--- | Three handles are allocated during program initialisation,
		-- and are initially open.

	  --- | RP_stdin, RP_stdout, RP_stderr -- :: Handle
      (RP_stdin , _) -> rsemPush $ RHsV_Handle stdin
      (RP_stdout, _) -> rsemPush $ RHsV_Handle stdout
      (RP_stderr, _) -> rsemPush $ RHsV_Handle stderr

      --- | RP_openFile                  -- :: FilePath -> IOMode -> IO Handle
      (RP_openFile, [fp, md]) -> primIO_2ArgVal1ResVal openFile fp md
      --- | RP_openBinaryFile                  -- :: FilePath -> IOMode -> IO Handle
      (RP_openBinaryFile, [fp, md]) -> primIO_2ArgVal1ResVal openBinaryFile fp md

	  -- IOMode(ReadMode,WriteMode,AppendMode,ReadWriteMode),

		--- ** Closing files

	  --- | RP_hClose                    -- :: Handle -> IO ()
      (RP_hClose, [RHsV_Handle h]) -> primIO (hClose h)

		--- * Operations on handles

		--- ** Determining and changing the size of a file

	  --- | RP_hFileSize                 -- :: Handle -> IO Integer
      (RP_hFileSize, [RHsV_Handle h]) -> primIO_0Arg1ResVal (hFileSize h)
	--- #ifdef __GLASGOW_HASKELL__
	  --- | RP_hSetFileSize              -- :: Handle -> Integer -> IO ()
      (RP_hSetFileSize, [RHsV_Handle h, RVal_Integer i]) -> primIO (hSetFileSize h i)
	--- #endif

		--- ** Detecting the end of input

	  --- | RP_hIsEOF                    -- :: Handle -> IO Bool
      (RP_hIsEOF, [h]) -> primIO_1ArgVal1ResVal hIsEOF h

		--- ** Buffering operations

	  -- BufferMode(NoBuffering,LineBuffering,BlockBuffering),
	  --- | RP_hSetBuffering             -- :: Handle -> BufferMode -> IO ()
      (RP_hSetBuffering, [h, m]) -> primIO_2ArgVal0Res hSetBuffering h m
	  --- | RP_hGetBuffering             -- :: Handle -> IO BufferMode
      (RP_hGetBuffering, [h]) -> primIO_1ArgVal1ResVal hGetBuffering h
	  --- | RP_hFlush                    -- :: Handle -> IO ()
      (RP_hFlush, [RHsV_Handle h]) -> primIO (hFlush h)

		--- ** Repositioning handles

	  -- HandlePosn,                -- abstract, instance of: Eq, Show.

	  -- SeekMode(AbsoluteSeek,RelativeSeek,SeekFromEnd),
	  --- | RP_hSeek                     -- :: Handle -> SeekMode -> Integer -> IO ()
      (RP_hSeek, [h, m, i]) -> primIO_3ArgVal0Res hSeek h m i
	-- #if !defined(__NHC__)
	  --- | RP_hTell                     -- :: Handle -> IO Integer
      (RP_hTell, [h]) -> primIO_1ArgVal1ResVal hTell h
	-- #endif

		--- ** Handle properties

	  --- | RP_hIsOpen
      (RP_hIsOpen, [h]) -> primIO_1ArgVal1ResVal hIsOpen h

	  --- | RP_hIsClosed        -- :: Handle -> IO Bool
      (RP_hIsClosed, [h]) -> primIO_1ArgVal1ResVal hIsClosed h

	  --- | RP_hIsReadable
      (RP_hIsReadable, [h]) -> primIO_1ArgVal1ResVal hIsReadable h

	  --- | RP_hIsWritable  -- :: Handle -> IO Bool
      (RP_hIsWritable, [h]) -> primIO_1ArgVal1ResVal hIsWritable h

	  --- | RP_hIsSeekable               -- :: Handle -> IO Bool
      (RP_hIsSeekable, [h]) -> primIO_1ArgVal1ResVal hIsSeekable h


{-
		--- ** Terminal operations (not portable: GHC\/Hugs only)

	--- #if !defined(__NHC__)
	  | RP_hIsTerminalDevice          -- :: Handle -> IO Bool

	  | RP_hSetEcho                   -- :: Handle -> Bool -> IO ()
	  | RP_hGetEcho                   -- :: Handle -> IO Bool
	--- #endif

		--- ** Showing handle state (not portable: GHC only)

	-- #ifdef __GLASGOW_HASKELL__
-}
	  --- | RP_hShow                      -- :: Handle -> IO String
      (RP_hShow, [RHsV_Handle h]) -> primIO_0Arg1ResVal (hShow h)
{-
	--- #endif

		--- * Text input and output

		--- ** Text input
-}
	  --- | RP_hWaitForInput             -- :: Handle -> Int -> IO Bool
      (RP_hWaitForInput, [RHsV_Handle h, RVal_Int i]) -> primIO_0Arg1ResVal (hWaitForInput h i)
	  --- | RP_hGetChar                  -- :: Handle -> IO Char
      (RP_hGetChar, [RHsV_Handle h]) -> primIO_0Arg1ResVal (hGetChar h)
	  --- | RP_hGetLine                  -- :: Handle -> IO [Char]
      (RP_hGetLine, [RHsV_Handle h]) -> primIO_0Arg1ResVal (hGetLine h)
	  --- | RP_hLookAhead                -- :: Handle -> IO Char
      (RP_hLookAhead, [RHsV_Handle h]) -> primIO_0Arg1ResVal (hLookAhead h)
	  --- | RP_hGetContents              -- :: Handle -> IO [Char]
      (RP_hGetContents, [RHsV_Handle h]) -> primIO_0Arg1ResVal (hGetContents h)
{-
		--- ** Text output

-}
	  --- | RP_hPutChar                  -- :: Handle -> Char -> IO ()
      (RP_hPutChar, [RHsV_Handle h, x]) -> primIO_1ArgVal0Res (hPutChar h) x
	  --- | RP_hPutStr                   -- :: Handle -> [Char] -> IO ()
      (RP_hPutStr, [RHsV_Handle h, x]) -> primIO_1ArgVal0Res (hPutStr h) x

		--- * Binary input and output
	  --- | RP_hSetBinaryMode            -- :: Handle -> Bool -> IO ()
      (RP_hSetBinaryMode, [RHsV_Handle h, b]) -> primIO_1ArgVal0Res (hSetBinaryMode h) b
	  --- | RP_hPutBuf                   -- :: Handle -> Ptr a -> Int -> IO ()
      (RP_hPutBuf, [RHsV_Handle h, RHsV_Addr a, RVal_Int i]) -> primIO (hPutBuf h (Ptr a) i)
	  --- | RP_hGetBuf                   -- :: Handle -> Ptr a -> Int -> IO Int
      (RP_hGetBuf, [RHsV_Handle h, RHsV_Addr a, RVal_Int i]) -> primIO_0Arg1ResVal (hGetBuf h (Ptr a) i)
{-
	--- #if !defined(__NHC__) && !defined(__HUGS__)
-}
	  --- | RP_hPutBufNonBlocking        -- :: Handle -> Ptr a -> Int -> IO Int
      (RP_hPutBufNonBlocking, [RHsV_Handle h, RHsV_Addr a, RVal_Int i]) -> primIO (hPutBufNonBlocking h (Ptr a) i)
	  --- | RP_hGetBufNonBlocking        -- :: Handle -> Ptr a -> Int -> IO Int
      (RP_hGetBufNonBlocking, [RHsV_Handle h, RHsV_Addr a, RVal_Int i]) -> primIO_0Arg1ResVal (hGetBufNonBlocking h (Ptr a) i)
{-
	--- #endif
-}
		--- * Temporary files

      --- | RP_openTempFile                  -- :: FilePath -> String -> IO (FilePath, Handle)
      (RP_openTempFile, [fp, tmpl]) -> primIO_2ArgVal1ResVal openTempFile fp tmpl
      --- | RP_openBinaryTempFile                  -- :: FilePath -> String -> IO (FilePath, Handle)
      (RP_openBinaryTempFile, [fp, tmpl]) -> primIO_2ArgVal1ResVal openBinaryTempFile fp tmpl

        --- * Additional ones
      --- | RP_primShowHandle               -- :: Handle -> String
      (RP_primShowHandle, [RHsV_Handle h]) -> hsUnmarshall $ show h
      --- | RP_primEqHandle                 -- :: Handle -> Handle -> Bool
      (RP_primEqHandle, [RHsV_Handle h1, RHsV_Handle h2]) -> hsUnmarshall $ h1 == h2

      (pr, _) -> err $ "CoreRun.Run.Val.Prim:" >#< show pr

{-# LINE 306 "src/ehc/CoreRun/Run/Val/Prim.chs" #-}
-- | Voidify IO on RVal level, i.e. make IO ()
-- rvalVoid :: (RunSem RValCxt RValEnv RVal m RVal) => RValT m a -> RValT m RVal
rvalVoid :: (RunSem RValCxt RValEnv RVal m a) => RValT m b -> RValT m a
rvalVoid m = m >> mkUnit
{-# INLINE rvalVoid #-}

-- | IO, no result
primIO :: (RunSem RValCxt RValEnv RVal m a) => IO x -> RValT m a
primIO io = rvalVoid $ liftIO $ io
-- {-# INLINE primIO #-}

-- | IO, taking 0 arg yielding a result
primIO_0Arg1ResVal :: (RunSem RValCxt RValEnv RVal m a, HSMarshall x) => IO x -> RValT m a
primIO_0Arg1ResVal io = (liftIO $ io) >>= hsUnmarshall
-- {-# INLINE primIO_0Arg1ResVal #-}

-- | IO, taking 1 (still to marshall) arg yielding ()
primIO_1ArgVal0Res :: (RunSem RValCxt RValEnv RVal m a, HSMarshall x) => (x -> IO ()) -> RVal -> RValT m a
primIO_1ArgVal0Res io x = do
  x' <- hsMarshall rvalPrimargEvl x
  rvalVoid $ liftIO $ io x'
-- {-# INLINE primIO_1ArgVal0Res #-}

-- | IO, taking 2 (still to marshall) arg yielding ()
primIO_2ArgVal0Res :: (RunSem RValCxt RValEnv RVal m a, HSMarshall x, HSMarshall y) => (x -> y -> IO ()) -> RVal -> RVal -> RValT m a
primIO_2ArgVal0Res io x y = do
  x' <- hsMarshall rvalPrimargEvl x
  y' <- hsMarshall rvalPrimargEvl y
  rvalVoid $ liftIO $ io x' y'
-- {-# INLINE primIO_2ArgVal0Res #-}

-- | IO, taking 3 (still to marshall) arg yielding ()
primIO_3ArgVal0Res :: (RunSem RValCxt RValEnv RVal m a, HSMarshall x, HSMarshall y, HSMarshall z) => (x -> y -> z -> IO ()) -> RVal -> RVal -> RVal -> RValT m a
primIO_3ArgVal0Res io x y z = do
  x' <- hsMarshall rvalPrimargEvl x
  y' <- hsMarshall rvalPrimargEvl y
  z' <- hsMarshall rvalPrimargEvl z
  rvalVoid $ liftIO $ io x' y' z'
-- {-# INLINE primIO_3ArgVal0Res #-}

-- | IO, taking 1 (still to marshall) arg yielding a result
primIO_1ArgVal1ResVal :: (RunSem RValCxt RValEnv RVal m a, HSMarshall x, HSMarshall res) => (x -> IO res) -> RVal -> RValT m a
primIO_1ArgVal1ResVal io x = hsMarshall rvalPrimargEvl x >>= (liftIO . io) >>= hsUnmarshall
-- {-# INLINE primIO_1ArgVal0Res #-}

-- | IO, taking 1 (still to marshall) arg yielding a result
primIO_2ArgVal1ResVal :: (RunSem RValCxt RValEnv RVal m a, HSMarshall x, HSMarshall y, HSMarshall res) => (x -> y -> IO res) -> RVal -> RVal -> RValT m a
primIO_2ArgVal1ResVal io x y = do
  x' <- hsMarshall rvalPrimargEvl x
  y' <- hsMarshall rvalPrimargEvl y
  liftIO (io x' y') >>= hsUnmarshall
-- {-# INLINE primIO_2Arg0Res #-}

{-# LINE 365 "src/ehc/CoreRun/Run/Val/Prim.chs" #-}
deriving instance Generic IOMode
instance HSMarshall IOMode

deriving instance Generic BufferMode
instance HSMarshall BufferMode

deriving instance Generic SeekMode
instance HSMarshall SeekMode

instance HSMarshall a => HSMarshall (Maybe a)

instance HSMarshall Ordering

instance (HSMarshall a, HSMarshall b) => HSMarshall (a,b)
instance (HSMarshall a, HSMarshall b, HSMarshall c) => HSMarshall (a,b,c)
instance (HSMarshall a, HSMarshall b, HSMarshall c, HSMarshall d) => HSMarshall (a,b,c,d)
instance (HSMarshall a, HSMarshall b, HSMarshall c, HSMarshall d, HSMarshall e) => HSMarshall (a,b,c,d,e)