packages feed

lhc-0.10: src/Grin/Lowering/Apply.hs

{-# LANGUAGE OverloadedStrings #-}
module Grin.Lowering.Apply
    ( lower
    ) where

import CompactString
import Grin.Types

import Control.Monad.Writer
import Control.Monad.State


lower :: Grin -> Grin
lower grin
    = case runState (execWriterT (lowerGrin grin)) (grinUnique grin) of
        ((newDefs),unique) -> grin { grinUnique    = unique
                                   , grinFunctions = appEndo newDefs [] }



type Lower a = WriterT (Endo [FuncDef]) (State Int) a

lowerGrin :: Grin -> Lower ()
lowerGrin grin
    = mapM_ lowerFuncDef (grinFunctions grin)

lowerFuncDef :: FuncDef -> Lower ()
lowerFuncDef def
    = do body <- lowerExpression (funcDefBody def)
         tell $ Endo $ \lst -> def{funcDefBody = body}:lst

lowerExpression :: Expression -> Lower Expression
lowerExpression (e :>>= v :-> t)
    = do e' <- lowerExpression e
         t' <- lowerExpression t
         return (e' :>>= v :-> t')
lowerExpression (e :>> t)
    = do e' <- lowerExpression e
         t' <- lowerExpression t
         return (e' :>> t')
lowerExpression (Application fn args)
    = do return $ Application fn args
lowerExpression (Case v alts)
    = do alts' <- mapM lowerAlt alts
         return $ Case v alts'
lowerExpression (Store v)
    = liftM Store (lowerValue v)
lowerExpression e@Update{}
    = return e
lowerExpression (Unit v)
    = liftM Unit (lowerValue v)

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


lowerValue :: Value -> Lower Value
lowerValue (Node (Builtin "evalApply") FunctionNode 0 [a,b])
    = do name <- newApplyFunction
         return $ Node name FunctionNode 0 [a,b]
lowerValue (Node (Builtin "evalApply") _ _ _)
    = error "Grin.Lowering.Apply.lowerValue: Weird apply."
lowerValue (Node name con missing args)
    = do return $ Node name con missing args
lowerValue (Lit lit)    = return $ Lit lit
lowerValue (Vector vs)  = return $ Vector vs
lowerValue (Variable v) = return $ Variable v
lowerValue (Hole size)  = return $ Hole size
lowerValue (Empty)      = return Empty


newApplyFunction
    = do name <- newVariable "apply"
         fnArg <- newVariable "fn"
         valArg <- newVariable "val"
         fn'Arg <- newVariable "fn'"
         tell $ Endo $ \lst -> FuncDef { funcDefName = name
                                       , funcDefArgs = [fnArg, valArg]
                                       , funcDefBody = Application (Builtin "eval") [fnArg] :>>= fn'Arg :-> Application (Builtin "apply") [fn'Arg, valArg]
                                       } : lst
         return name

newVariable :: CompactString -> Lower Renamed
newVariable alias
    = do u <- get
         put (u+1)
         return $ Aliased u alias