{-# OPTIONS -O0 #-} 

module Curry.RunTimeSystem (
  module Curry.RunTimeSystem.BaseCurry,
  module Curry.RunTimeSystem
  ) where

import System.IO
import Curry.RunTimeSystem.BaseCurry
import System.IO.Unsafe
import Data.IORef

-------------------------------------------------
-- normal forms which are all based on ctcStore
-- and may be called from compiled programs.
-------------------------------------------------


--SHOCKING: there was an additional ctcStore False (nf ...) around here, 
-- runtimes were desastrous. Why was that??????
nfCTC :: (BaseCurry a,BaseCurry b) => (b -> Result a) -> b -> Result a
nfCTC cont = ctcStore False (nf cont)

hnfCTC :: (BaseCurry a,BaseCurry b) => (b -> Result a) -> b -> Result a 
hnfCTC = ctcStore False 

gnfCTC :: (BaseCurry a,BaseCurry b) => (b -> Result a) -> b -> Result a
gnfCTC cont = ctcStore True (gnf cont)

ghnfCTC :: (BaseCurry a,BaseCurry b) => (b -> Result a) -> b -> Result a 
ghnfCTC = ctcStore True

-----------------------------------------------------------------
-- treatment for the basic cases of flexible pattern matching
-----------------------------------------------------------------

-- called by generated functions for matching failure
patternFail :: (BaseCurry a,BaseCurry b) => String -> a -> b
patternFail s x = case consKind x of
  Failed -> addException (curryError s) x
  _      -> failed (PatternMatchFail s)


----------------------------------------------------------------------
-- generate logic objects
----------------------------------------------------------------------

-- generate branching
withRef :: (Int -> a) -> Int -> a 
withRef f 0 = f 0
withRef f i = f $! nextRef i

---------------------------------------------------------------
-- manipulating references: the unsafe part of CurryToHaskell
---------------------------------------------------------------

-- the global state of references
storeRefCounter :: IORef Int
{-# NOINLINE storeRefCounter #-}
storeRefCounter = unsafePerformIO (newIORef 1)

-- generate a new reference
nextRef :: Int -> Int 
{-# NOINLINE nextRef #-}
nextRef i = unsafePerformIO (do 
               v <- readIORef storeRefCounter
               writeIORef storeRefCounter (v+i+1)
               return v)

---------------------------------------------------------------
-- run-time options (also unsafe)
---------------------------------------------------------------

-- the easiest way to have different modes for run-time behaviour is
-- a global state of run-time options.
-- the settings are only read once and stay the same during the whole computation.

data RunTimeOptions = RTO {currentModule :: String}

runTimeDefaults :: RunTimeOptions
runTimeDefaults = RTO {currentModule = ""} 

runTimeOptions :: IORef RunTimeOptions
{-# NOINLINE runTimeOptions #-}
runTimeOptions = unsafePerformIO (newIORef runTimeDefaults)

setRunTimeOptions :: RunTimeOptions -> IO ()
setRunTimeOptions = writeIORef runTimeOptions 

freeF :: (BaseCurry b, BaseCurry a) => (b -> a) -> a
freeF = freeOrBased

orF :: BaseCurry a => a -> a -> a
orF = orCTC

-----------------------------------------------------------------------
-- implementation of getProgName (module System) expressions
-----------------------------------------------------------------------

setProgName :: String -> IO ()
setProgName n = do 
  opts <- readIORef runTimeOptions
  writeIORef runTimeOptions (opts{currentModule=n})

setProgNameAndOrBased :: String -> IO ()
setProgNameAndOrBased = setProgName

getProgName :: IO String
getProgName = readIORef runTimeOptions >>= return . currentModule

----------------------------------------------------------------------
-- alternatives for implementation of options
----------------------------------------------------------------------

orCTC :: BaseCurry a => a -> a -> a
orCTC x y = branching (mkRefWithGenInfo NoGenerator (nextRef 0)) [x,y]

-- free variables in or-based mode
freeOrBased :: (BaseCurry b, BaseCurry a) => (b -> a) -> a
freeOrBased f = f (generator (nextRef 0))

----------------------------------------------------------
-- some declarations for external read and show instances
----------------------------------------------------------

ten,eleven,zero :: Int
ten    = 10
eleven = 11
zero   = 0

readQualified :: String -> String -> String -> [((),String)]
readQualified mod name r =  [((),s)  | (name',s)  <- lex r, name' == name] 
                         ++ [((),s3) | (mod',s1)  <- lex r
                                     , mod' == mod
                                     , (".",s2)   <- lex s1
                                     , (name',s3) <- lex s2
                                     , name' == name]