packages feed

lhc-0.8: src/Grin/Lowering/GHCism.hs

{-# LANGUAGE OverloadedStrings, PatternGuards #-}
{- |
  The External Core output from GHC suffers from many GHCisms and the direct
  translation to GRIN results in incorrect code.
  This module clears out GHC specific patterns and returns GRIN code fit for use.
  CAUTION: This pass MUST be run exactly once from Grin.FromCore.
           Any deviation will mess things up.
-}
module Grin.Lowering.GHCism
    ( lower
    ) where

import CompactString
import Grin.Types

import Control.Monad.State
import Control.Monad.Reader
import qualified Data.Map as Map

lower :: Map.Map CompactString Renamed -> Grin -> Grin
lower scope grin
    = case runState (runReaderT (lowerGrin grin) emptyScope) (grinUnique grin) of
        (newGrin, unique) -> newGrin{grinUnique = unique}
    where emptyScope = Scope { scope = scope }

data Scope = Scope { scope :: Map.Map CompactString Renamed }
type Lower a = ReaderT Scope (State Int) a

lowerGrin :: Grin -> Lower Grin
lowerGrin grin
    = do defs <- mapM lowerFuncDef (grinFunctions grin)
         return grin{grinFunctions = defs}

lowerFuncDef :: FuncDef -> Lower FuncDef
lowerFuncDef def
    = do body <- lowerExpression (funcDefBody def)
         return def{funcDefBody = body}

lowerExpression :: Expression -> Lower Expression
lowerExpression (e :>>= lam)
    = do e' <- lowerExpression e
         lam' <- lowerLambda lam
         return $ e' :>>= lam'
lowerExpression (e :>> f)
    = do e' <- lowerExpression e
         f' <- lowerExpression f
         return $ e' :>> f'
lowerExpression (Application (Builtin fn) [a,b]) | Just renamed <- lookup fn renamedOpts
    = lowerExpression (Application (Builtin renamed) [a,b])
lowerExpression (Application (Builtin fn) [a,b]) | fn `elem` [">=#",">#","==#","<=#","<#"]
    = do tnode <- lookupNode $ fromString "ghc-prim:GHC.Bool.True"
         fnode <- lookupNode $ fromString "ghc-prim:GHC.Bool.False"
         v <- newVariable
         return $ Application (Builtin fn) [a,b] :>>= v :->
                  Case v [Lit (Lint 0) :> Unit (Node fnode ConstructorNode 0 [])
                         ,Lit (Lint 1) :> Unit (Node tnode ConstructorNode 0 [])]

-- MVars
lowerExpression (Application (Builtin "newMVar#") [realWorld])
    = do v <- newVariable
         return $ Store Empty :>>= v :-> Unit (Vector [realWorld, v])
lowerExpression (Application (Builtin "putMVar#") [ptr, val, realWorld])
    = return $ Application (Builtin "update") [ptr, val] :>> Unit (Variable realWorld)
lowerExpression (Application (Builtin "takeMVar#") [ptr, realWorld])
    = do v <- newVariable
         return $ Application (Builtin "fetch") [ptr] :>>= v :-> Unit (Vector [realWorld, v])

-- MutVars

lowerExpression (Application (Builtin "newMutVar#") [val,realWorld])
    = do v <- newVariable
         return $ Store (Variable val) :>>= v :-> Unit (Vector [realWorld, v])
lowerExpression (Application (Builtin "writeMutVar#") [ptr, val, realWorld])
    = return $ Application (Builtin "update") [ptr, val] :>> Unit (Variable realWorld)
lowerExpression (Application (Builtin "readMutVar#") [ptr, realWorld])
    = do v <- newVariable
         return $ Application (Builtin "fetch") [ptr] :>>= v :-> Unit (Vector [realWorld, v])

lowerExpression (Application (Builtin "realWorld#") [])
    = return $ Unit Empty -- FIXME: Use a special RealWorld value?
lowerExpression (Application (Builtin "int2Word#") [v])
    = return $ Unit (Variable v)
lowerExpression (Application (Builtin "word2Int#") [v])
    = return $ Unit (Variable v)
lowerExpression (Application (Builtin "plusAddr#") [a,b])
    = return $ Application (Builtin "+#") [a,b]
lowerExpression (Application (Builtin "eqAddr#") [a,b])
    = lowerExpression $ Application (Builtin "==#") [a,b]
--lowerExpression (Application (Builtin fn) [a]) | fn `elem` ["chr#", "ord#"]
--    = return $ Unit (Variable a)

lowerExpression (Application (Builtin "raiseIO#") [exp, realWorld])
    = return $ Application (Builtin "raise#") [exp]

lowerExpression (Application (Builtin "catch#") [fn, handler, realworld])
    = do v <- newVariable
         return $ Application (Builtin "eval") [fn] :>>= v :-> Application (Builtin "apply") [v, realworld]
lowerExpression (Application (Builtin "blockAsyncExceptions#") [fn, realworld])
    = do v <- newVariable
         return $ Application (Builtin "eval") [fn] :>>= v :-> Application (Builtin "apply") [v, realworld]
lowerExpression (Application (Builtin "unblockAsyncExceptions#") [fn, realworld])
    = do v <- newVariable
         return $ Application (Builtin "eval") [fn] :>>= v :-> Application (Builtin "apply") [v, realworld]

lowerExpression (Application fn vs)
    = return $ Application fn vs
lowerExpression (Case scrut alts)
    = do alts' <- mapM lowerAlt alts
         return $ Case scrut alts'
lowerExpression (Store v)
    = return $ Store v
lowerExpression (Unit v)
    = return $ Unit v

lowerLambda :: Lambda -> Lower Lambda
lowerLambda (v :-> e)
    = do e' <- lowerExpression e
         return $ v :-> e'
lowerAlt :: Alt -> Lower Alt
lowerAlt (v :> e)
    = do e' <- lowerExpression e
         return $ v :> e'


renamedOpts = [ ("gtChar#", ">#")
              , ("geChar#", ">=#")
              , ("ltChar#", "<#")
              , ("leChar#", "<=#")
              , ("eqChar#", "==#")
              ]



lookupNode :: CompactString -> Lower Renamed
lookupNode name
    = do m <- asks scope
         case Map.lookup name m of
           Just name -> return name
           Nothing   -> error $ "Couldn't find node: " ++ show name

newVariable :: Lower Renamed
newVariable
    = do u <- get
         put (u+1)
         return $ Anonymous u