ddc-tools-0.3.1.1: src/ddci-core/DDCI/Core/Command/Trans.hs
{-# OPTIONS -Werror #-}
module DDCI.Core.Command.Trans
( cmdTrans
, cmdTransEval
, applyTransAndCheck)
where
import DDCI.Core.Command.Eval
import DDCI.Core.Output
import DDCI.Core.State
import DDC.Driver.Command.Check
import DDC.Core.Fragment
import DDC.Core.Transform.Reannotate
import DDC.Core.Simplifier
import DDC.Core.Check
import DDC.Core.Exp
import DDC.Core.Compounds
import DDC.Type.Equiv
import DDC.Type.Subsumes
import DDC.Base.Pretty
import DDC.Type.Env as Env
import qualified Control.Monad.State.Strict as S
import qualified DDC.Build.Language.Eval as Eval
import qualified DDC.Core.Eval.Name as Eval
import qualified Data.Set as Set
import Data.Typeable
import Control.Monad
import DDC.Core.Module
-- Trans ----------------------------------------------------------------------
-- | Apply the current transform to an expression.
cmdTrans :: State -> Source -> String -> IO ()
cmdTrans state source str
| Language bundle <- stateLanguage state
, fragment <- bundleFragment bundle
, modules <- bundleModules bundle
, simpl <- bundleSimplifier bundle
, zero <- bundleStateInit bundle
, profile <- fragmentProfile fragment
= cmdParseCheckExp fragment modules True source str
>>= goStore profile modules zero simpl
where
-- Expression had a parse or type error.
goStore _ _ _ _ Nothing
= do return ()
-- Expression is well-typed.
goStore profile modules zero simpl (Just x)
= do let kenv = modulesExportKinds modules (profilePrimKinds profile)
let tenv = modulesExportTypes modules (profilePrimTypes profile)
tr <- applyTransAndCheck state profile kenv tenv zero simpl x
case tr of
Nothing -> return ()
Just x' -> outDocLn state $ ppr x'
-- TransEval ------------------------------------------------------------------
-- | Apply the current transform to an expression,
-- then evaluate and display the result
cmdTransEval :: State -> Source -> String -> IO ()
cmdTransEval state source str
| Language bundle <- stateLanguage state
, fragment <- bundleFragment bundle
, modules0 <- bundleModules bundle
, zero <- bundleStateInit bundle
, simpl0 <- bundleSimplifier bundle
, profile0 <- fragmentProfile fragment
-- The evaluator only works on expressions with Eval.Names,
-- The actual name type is an existential of Bundle,
-- so we use gcast to check whether the bundle is really
-- set to Eval.
, Just (profile :: Profile Eval.Name) <- gcast profile0
, Just (SimplBox simpl) <- gcast (SimplBox simpl0)
, Just (modules :: ModuleMap (AnTEC () Eval.Name) Eval.Name)
<- gcast modules0
= do result' <- cmdParseCheckExp Eval.fragment modules False source str
case result' of
Nothing -> return ()
Just xx
-> do let kenv = modulesExportKinds modules (profilePrimKinds profile)
let tenv = modulesExportTypes modules (profilePrimTypes profile)
-- Apply the current transform.
tr <- applyTransAndCheck state profile kenv tenv zero simpl xx
case tr of
Nothing -> return ()
Just x'
-- Evaluate the transformed expression.
-> do outDocLn state $ ppr x'
evalExp state x'
return ()
| otherwise
= outDocLn state $ text "Language must be set to Eval for :teval"
-- Proxies to help with type casting.
-- The 'gcast' function will only cast the rightmost 'n' of a type,
-- But there is also an 'n' attached to the annotation type of
-- the simplifier. We use the proxy to cast both occurrences at once.
data SimplBox s n
= SimplBox (Simplifier s (AnTEC () n) n)
-- Trans ----------------------------------------------------------------------
-- | Transform an expression, or display errors
applyTransAndCheck
:: (Eq n, Ord n, Pretty n, Show n, Show a)
=> State
-> Profile n
-> Env n -- Kind Environment.
-> Env n -- Type Environment.
-> s
-> Simplifier s (AnTEC a n) n
-> Exp (AnTEC a n) n
-> IO (Maybe (Exp (AnTEC () n) n))
applyTransAndCheck state profile kenv tenv zero simpl xx
= do
let Just annot = takeAnnotOfExp xx
let t1 = annotType annot
let eff1 = annotEffect annot
let clo1 = annotClosure annot
-- Apply the simplifier.
let tx = flip S.evalState zero
$ applySimplifierX profile kenv tenv simpl xx
let x' = reannotate (const ()) $ result tx
when (Set.member TraceTrans $ stateModes state)
$ case (resultInfo tx) of
TransformInfo inf
-> outDocLn state
$ text "* TRANSFORM INFORMATION: " <$> indent 4 (ppr inf) <$> text ""
-- Check that the simplifier perserved the type of the expression.
case checkExp (configOfProfile profile) kenv tenv x' of
Right (x2, t2, eff2, clo2)
| equivT t1 t2
, subsumesT kEffect eff1 eff2
, subsumesT kClosure clo1 clo2
-> do return (Just x2)
| otherwise
-> do putStrLn $ renderIndent $ vcat
[ text "* CRASH AND BURN: Transform is not type preserving."
, ppr x'
, text ":: 1 " <+> ppr t1
, text ":: 2 " <+> ppr t2
, text ":!:1 " <+> ppr eff1
, text ":!:2 " <+> ppr eff2
, text ":$:1 " <+> ppr clo1
, text ":$:2 " <+> ppr clo2 ]
return Nothing
Left err
-> do putStrLn $ renderIndent $ vcat
[ text "* CRASH AND BURN: Type error in transformed program."
, ppr err
, text "" ]
outDocLn state $ text "Transformed expression:"
outDocLn state $ ppr x'
return Nothing