-- 
-- (c) Susumu Katayama
--
{-# OPTIONS -fth -fglasgow-exts -cpp #-}
-- compile with  -package ghc
module MagicHaskeller.ExecuteAPI610  {- (loadObj, prepareAPI, executeAPI, unsafeExecuteAPI) -} where
import qualified HscMain
import GHC
import GHC.Exts
import GHC.Paths(libdir) -- as instructed in http://haskell.org/haskellwiki/GHC/As_a_library
import DynFlags         -- (DynFlag, defaultDynFlags, PackageFlag(ExposePackage)) -- , glasgowExtsFlags) はexportされていないらしい.
import SrcLoc           (SrcSpan(..), noSrcSpan, noSrcLoc, interactiveSrcLoc, Located(L),  noLoc)

-- import MyCorePrep		( corePrepExpr )
import CorePrep(corePrepExpr) -- コンパイルが通らないのでオリジナルにしてみる

import FastString
import ByteCodeGen	( coreExprToBCOs )

-- import MyLink		-- ( HValue, linkExpr, initDynLinker )
import Linker -- コンパイルが通らないのでオリジナルにしてみる

-- import Flattening
import HscTypes        -- ( HscEnv(..), Session(..), withSession, InteractiveContext(..), mkTypeEnv ) -- also import instance MonadIO Ghc
import SimplCore
-- import SimplOnce -- コンパイルが通らないのでコメントアウト
import VarEnv		( emptyTidyEnv )
import CoreSyn		( CoreExpr, Expr(..), Bind(..) )     -- compiler/coreSyn/CoreSyn.lhs
import CoreTidy		( tidyExpr )


import Parser           (parseStmt)
import Lexer
import TcRnDriver	( tcRnStmt, tcRnExpr, tcRnType ) 
import Desugar          (deSugarExpr)
import PrelNames	( iNTERACTIVE )
import ErrUtils
import StringBuffer     (stringToStringBuffer)
import Outputable       (ppr, pprPanic, showSDocDebug, showSDoc)
import TypeRep          (pprType, Type)

import CoreLint         (lintUnfolding)
import VarSet           (varSetElems)
import Panic            (panic)

import Var              -- (Var(..))

import System.IO
import System.IO.Unsafe

import Data.IORef

import System.Exit
import Control.Monad(when)
-- import Control.Monad.Trans(liftIO)

import MagicHaskeller.MyDynamic
import qualified MagicHaskeller.CoreLang as CoreLang
import Language.Haskell.TH as TH hiding (ppr)

import Data.List(isSuffixOf)

#ifdef GHC6
-- prelude/TysPrim.
import TysPrim(anyPrimTy)
#endif

import Bag
import RdrName
import OccName
import Convert
import HsUtils
import HsExpr

-- 最後のCoreExpr ---> CoreExprで要るもの．
import IdInfo
import Data.Char(ord,chr)
import qualified Data.Map as Map
import qualified MagicHaskeller.Types as Types
import Data.List
import Unique
import Id

import UniqSupply

import ByteCodeLink(linkBCO,extendClosureEnv)
import ByteCodeAsm(UnlinkedBCO(unlinkedBCOName))

import Data.Array

-- #define PRELINK

pathToGHC :: FilePath    -- path to GHC, e.g. "/usr/lib/ghc-6.10.4". 'libdir' can be used instead.
pathToGHC = libdir

loadObj :: [String] -- ^ visible modules (including package modules). You may omit the Prelude.
           -> IO (CoreLang.VarLib -> CoreLang.CoreExpr -> Dynamic)
loadObj fss = fmap unsafeExecuteAPI $ prepareAPI fss

-- Just follow http://haskell.org/haskellwiki/GHC/As_a_library
-- 問題は，すでに読まれているmoduleはどうするかってことだけど，:loadコマンド同様再読み込み
{- addNonPackageTargetってのを定義したので，分ける必要はなくなったはず．
prepareAPI :: [FilePath] -- ^ modules to be loaded (except package modules)
           -> [FilePath] -- ^ visible modules (including package modules)
           -> IO Session
prepareAPI fss allfss
-}
prepareAPI :: [String] -- ^ visible modules (including package modules). 
                       --   Supplying @[]@ here works without any problems within GHCi, and currently @prepareAPI@ does not work without --interactive, 
                       --   so this argument is actually of no use:(
           -> IO HscEnv
prepareAPI fss
    = defaultErrorHandler defaultDynFlags $
       runGhc (Just pathToGHC) $ do
          -- liftIO $ hPutStrLn stderr "setting up flags"

          dfs     <- getSessionDynFlags
--          when (flags dfs /= flags defaultDynFlags) $ error "flags are different"
          let newf = dfs{opt_P = "-DTEMPLATE_HASKELL" : "-DCLASSIFY" : "-DCHTO" : opt_P dfs,           -- defaultDynFlagsのソースが結構参考になったり．
                         packageFlags = [ ExposePackage "ghc", ExposePackage "old-time", ExposePackage "ghc-paths" ]
                         {-
                         flags = Opt_TemplateHaskell  : Opt_Cpp : -- Opt_FlexibleInstances : Opt_ExistentialQuantification : Opt_PolymorphicComponents : Opt_RelaxedPolyRec :
                                 Opt_MagicHash :
                                 Opt_RankNTypes :
                                 filter (/=Opt_MonomorphismRestriction) (flags dfs) -}
                        } -- Was: Opt_TH   --  てゆーか，LibTHをここで読むにはいろんなフラグが....
          setSessionDynFlags newf   -- result abandoned
          -- ソースによると結果はDynamic linkingの時に必要ってことだけど，ま，基本的にはDynamic linkingはunsupportedってことか．
          -- http://hackage.haskell.org/trac/ghc/wiki/DynamicLinking
          -- ...違う．そのdynamic linkingではない．

          -- liftIO $ hPutStrLn stderr "loading modules" -- This IS necessary.
          ts <- mapM (\fs -> guessTarget fs Nothing) fss
          setTargets ts
          sf <- defaultCleanupHandler newf (load LoadAllTargets)
          case sf of Succeeded -> return ()
                     Failed    -> error "failed to load modules"

          -- liftIO $ hPutStrLn stderr "setting up modules********************************************************"
#ifdef GHC7
          modules <- mapM (\fs -> fmap (\x -> (x,Nothing)) $ findModule (mkModuleName fs) Nothing) ("Prelude":fss)
#else
          modules <- mapM (\fs -> findModule (mkModuleName fs) Nothing) ("Prelude":fss)
#endif
          setContext [] modules

#ifdef PRELINK
          -- prelink!
          newdfs     <- getSessionDynFlags
          initDynLinker newdfs
#endif

          getSession
{-
-- | @addNonPackageTarget@ adds a target only if the target is not a package module.
--   This function assumes there is no package module in the target set of the session.
addNonPackageTarget :: Target -> IO ()
addNonPackageTarget target@(Target targetid _)
    = catchDyn (addTarget target >> depanal [] False >> return ())
               (\str -> if "is a package module" `isSuffixOf` str then removeTarget targetid else throwDyn str)
-- depanalがNothingを返す場合，結局後のloadがfailする訳だが，面倒なのでこの段階では放置プレイってことで．
-}

-- At least I should use a customized version of toString....
unsafeExecuteAPI :: HscEnv -> CoreLang.VarLib -> CoreLang.CoreExpr -> Dynamic
unsafeExecuteAPI session vl cece = unsafeToDyn undefined undefined (unsafeCoerce# $ unsafePerformIO $ executeAPI session vl cece) undefined -- unsafeCoerce# is necessary to convert from Dynamic.HValue to HValue.
executeAPI :: HscEnv -> CoreLang.VarLib -> CoreLang.CoreExpr -> IO a
executeAPI session vl cece = executeTHExp session (CoreLang.exprToTHExp vl cece)
executeTHExp :: HscEnv -> TH.Exp -> IO a
executeTHExp session the = unwrapCore session =<< compileCoreExpr session the


compileCoreExpr ::  HscEnv -> TH.Exp -> IO CoreSyn.CoreExpr 
compileCoreExpr hscEnv the
    = -- defaultErrorHandler defaultDynFlags $ -- thread killed を表示させたい場合はこっち．
{-
       do res <- compileExpr session $ TH.pprint $ CoreLang.exprToTHExp cece
          case res of Nothing -> hPutStrLn stderr "Could not execute" >> error "could not execute"
                      Just hv -> return hv
-}


--       do mbt <- strToCore hscEnv ("let __cmCompileExpr = " ++ TH.pprint the)

       do mbt <- stmtToCore hscEnv $ wrapLHsExpr $ thExpToLHsExpr the
          case mbt of Nothing -> error ("could not compile " ++ TH.pprint the ++ " to core.")
                      Just ([i ], ce) -> return ce


-- unwrapCore, unwrapCore' の両方が正しく動く．unwrapCoreはghc6.8で動いていたのを持ってきたもので，compileExprHscMainの方をコメントアウトしてrunCoreExprにすると色々はしょる代わりに正しく動かない．
unwrapCore, unwrapCore' :: HscEnv -> CoreSyn.CoreExpr -> IO a
unwrapCore hscEnv ce =                  do -- iohvs <- runCoreExpr hscEnv ce -- (removeIdInfo ce)
                                           iohvs <- unsafeCoerce# $ compileExprHscMain hscEnv ce
                                           [hv] <- iohvs
                                           return hv

unwrapCore' hscEnv ce = fmap head $ unsafeCoerce# =<< HscMain.compileExpr hscEnv (srcLocSpan interactiveSrcLoc) ce


runCoreExpr, runPrepedCoreExpr :: HscEnv -> CoreExpr -> IO a
runCoreExpr hscEnv ce
    = -- repeatIO 10 $
      do
         let dfs = hsc_dflags hscEnv
         pe <- corePrepExpr dfs ce -- runPrepedCoreExprとの違いはこのcorePrepExprがあるかどうかだけ

         bcos <- -- repeatIO 10 $
                 coreExprToBCOs dfs pe

#ifdef PRELINK
         hv <- linkTheExpr bcos
#else
         hv <-linkExpr hscEnv noSrcSpan bcos
#endif
         return $ unsafeCoerce# hv

runPrepedCoreExpr hscEnv ce
    = -- repeatIO 10 $
      do
         let dfs = hsc_dflags hscEnv

         bcos <- coreExprToBCOs dfs ce
         -- repeatIO 10 $
#ifdef PRELINK
         hv <- linkTheExpr bcos
#else
         hv <-linkExpr hscEnv noSrcSpan bcos
#endif
         return $ unsafeCoerce# hv

#ifdef PRELINK
-- | If already prelinked linkTheExpr can be used in place of linkExpr.
linkTheExpr :: UnlinkedBCO -> IO HValue
linkTheExpr ulbco
    = do pls <- readIORef v_PersistentLinkerState
         let ie = itbl_env pls
             ce = closure_env pls
             nm = unlinkedBCOName ulbco
         fixIO (\hv -> linkBCO ie (extendClosureEnv ce [(nm,hv)]) ulbco)
#endif


stmtToCore hscEnv pst = do let dfs  = hsc_dflags hscEnv
                               icxt = hsc_IC     hscEnv
                           -- hPutStrLn stderr "*************************************"
                           -- hPutStrLn stderr $ showSDoc $ ppr pst
	                   (tcmsgs, mbtc) <- tcRnStmt hscEnv icxt pst
                           case mbtc of Nothing             -> perror dfs tcmsgs
                                        Just (ids, tc_expr) -> do -- desugar
                                          let typeEnv = mkTypeEnv (map AnId (ic_tmp_ids icxt))
                                          (desmsgs, mbds) <- deSugarExpr hscEnv iNTERACTIVE (ic_rn_gbl_env icxt) typeEnv tc_expr
                                          case mbds of Nothing -> perror dfs desmsgs
                                                       Just ds -> return (Just (ids, ds))
perror dfs msg = printErrorsAndWarnings dfs msg >> return Nothing

unwrapLStmt (L _ (LetStmt (HsValBinds (ValBindsIn bg _)))) = unL $ head $ bagToList bg
unL (L _ x) = x

thExpToStmt :: TH.Exp -> HsExpr.LStmt RdrName.RdrName
thExpToStmt = wrapLHsExpr . thExpToLHsExpr
wrapLHsExpr ::  HsExpr.LHsExpr RdrName.RdrName -> HsExpr.LStmt RdrName.RdrName
wrapLHsExpr expr = noLoc $ LetStmt (HsValBinds (ValBindsIn (Bag.unitBag (HsUtils.mk_easy_FunBind noSrcSpan (Unqual $ mkOccName OccName.varName "__cmCompileExpr") [] expr)) []))
thExpToLHsExpr :: TH.Exp -> HsExpr.LHsExpr RdrName.RdrName
thExpToLHsExpr e = case Convert.convertToHsExpr noSrcSpan e of
		    Left  msg -> error $ showSDoc msg 
		    Right expr -> expr

instance Show b => Show (Expr b) where
    showsPrec p (Var var) = ("Var "++) . (showSDocDebug (ppr var) ++)
    showsPrec _ (Lit l)   = ("Lit "++) . shows l
    showsPrec _ (App e0@(App _ _) e1) = shows e0 . (" `App` "++) . showParen True (shows e1)
    showsPrec _ (App e0 e1)           = showParen True (shows e0) . (" `App` "++) . showParen True (shows e1)
    showsPrec _ (Lam v e)             = ('\\':) . shows v . shows e
    showsPrec _ (Let bs e)            = ("let"++) . shows bs . (" in "++) . shows e
    showsPrec _ (Case _ _ _ _) = ("case"++)
    showsPrec _ (Cast e t)     = ("Cast "++) . showParen True (shows e) . ("<Coercion>"++)
    showsPrec _ (Note _ _)     = ("Note"++)
    showsPrec _ (Type t)       = (showSDoc (pprType t) ++)
instance Show b => Show (Bind b) where
    showsPrec _ (NonRec b e) = (' ':) . shows b . (" = "++) . shows e
    showsPrec _ (Rec ts )    = ("rec { "++) . foldr (.) id (map hoge ts) . (" } "++)
hoge :: Show b => (b, Expr b) -> ShowS
hoge (b, e) = shows b . (" = "++) . shows e . (" ; "++)


{- unused. also, anyPrimTy does not appear in ghc-7.* any longer
-- remove the type info to see if they are necessary even when there is no ad-hoc polymorphism
removeTInfo :: Expr b -> Expr b
removeTInfo (App e0 e1) = App (removeTInfo e0) (removeTInfo e1)
removeTInfo (Lam v e)   = Lam v (removeTInfo e)
removeTInfo (Let bs e)  = Let (rtis bs) (removeTInfo e)
removeTInfo (Type t)    = Type anyPrimTy
removeTInfo (Cast e t)  = Cast (removeTInfo e) t
removeTInfo e           = e

rtis (NonRec b e) = NonRec b (removeTInfo e)
rtis (Rec    ts)  = Rec [ (b, removeTInfo e) | (b,e) <- ts ]
-}

compileExprHscMain :: HscEnv -> CoreExpr -> IO HValue
compileExprHscMain hscEnv ce
  =  do	let dflags  = hsc_dflags hscEnv
	smpl <- simplifyExpr   dflags ce
	prep <- corePrepExpr   dflags smpl
	bcos <- coreExprToBCOs dflags prep
	linkExpr hscEnv noSrcSpan bcos

#ifdef GHC6
{-
directLoadObj :: [String] -- ^ visible modules (including package modules). You may omit the Prelude.
           -> [(a, TH.Exp, TH.Type)]
           -> IO (CoreLang.CoreExpr -> Dynamic)
directLoadObj fss tups
    = defaultErrorHandler defaultDynFlags $ do
        hscEnv <- prepareAPI fss

#ifdef PRELINK
        hPutStrLn stderr "prelink! (temporarily)"
        compileExpr hscEnv "([], (:), list_para)"
--        compileExpr session "([]::[a], (:)::a->[a]->[a], list_para::[b]->a->(b->[b]->a->a)->a)"
--          compileExpr "([]::[Char], (:)::Char->[Char]->[Char], list_para::[Char]->Int->
#endif

        gm <- mkGlobalAr hscEnv tups
        return $ unsafeDirectExecuteAPI hscEnv gm
-}
unsafeDirectExecuteAPI hscEnv gm ce = unsafePerformIO $ directExecuteAPI hscEnv gm ce
directExecuteAPI :: HscEnv -> GlobalAr -> CoreLang.CoreExpr -> IO a
directExecuteAPI hscEnv gm ce
    = runCoreExpr hscEnv $ ceToCSCE gm ce

-- Note: MagicHaskeller.Primitive = (HValue, TH.Exp, TH.Type)
-- Use
--  typeToTHType :: TyConLib -> Types.Type -> TH.Type
-- if necessary. TyConLib can be undefined here.
compileVar :: HscEnv -> (a, TH.Exp, TH.Type) -> IO CoreSyn.CoreExpr
compileVar hscEnv (_, the, ty)
    = do csce <- compileCoreExpr hscEnv the -- これだと，[| (==)::Char->Char->Bool |]みたいな場合にtheが単にVarE '(==)になってうまくいかない．(ad hocなtyvarがinstantiateされない)
         -- Just (_,csce) <- strToCore session ("let __compileExpr = ("++TH.pprint the ++")::"++TH.pprint (unforall ty))
         let unr = unwrap csce
         putStrLn ("csce = "++show unr)
	 case ty of TH.ForallT tvs [] _ -> do let dfs = hsc_dflags hscEnv
                                              simplifyExpr dfs $ foldl CoreSyn.App unr $ replicate (length tvs) $ CoreSyn.Type anyPrimTy
                                              -- CorePrep は 不要なはずではあるが，どうするよ？
                    _                   -> return unr
unwrap (Let (Rec ((_,e):_)) _) = e
-- unwrap (Let (Rec [(_,e)]) _) = e -- こっちだとなぜかダメで，その辺にバグのにほひが....
unwrap st                    = error (show st)
unforall (TH.ForallT _ _ t) = t
unforall t = t

type GlobalMap = Map.Map String CoreSyn.CoreExpr -- Stringの代わりにTH.Nameなどにしようとすると，ちゃんとequivalenceが思い通りの結果になってくれない．．
mkGlobalMap :: HscEnv -> [(a, TH.Exp, TH.Type)] -> IO GlobalMap
-- てゆーか，CoreLang.CoreExprのPrimitiveがCoreSyn.CoreExprの情報を持つのが速い．
-- data CoreExpr a = ... みたいにして，CoreExpr CoreSyn.CoreExprみたいに使う．
mkGlobalMap hscEnv tups =  do ces <- mapM (compileVar hscEnv) tups
                              return $ Map.fromList $ zip (map (\(_,b,_) -> thToBaseString b) tups) ces

{-
-- See Linker.linkDependencies
linkDeps :: Session -> [Module] -> IO Bool
linkDeps session mods = 

てゆーか最初に"([],(:),list_para,lines,take)"みたいなのをcompileExprしてしまえばprelinkされるのでは？


-- obtain the set of modules required to be linked
cscesToNeededModules :: [CoreSyn.CoreExpr] -> [Module]
cscesToNeededModules csces = [ GHC.nameModule n | csce <- csces,
                                                  var  <- csceToVars' csce [],
                                                  let n = Var.varName n,
                                                  isExternalName n,
                                                  not (isWiredInName n) ]

-- Should I define instance Generic (Expr b)?
csceToVars' :: CoreSyn.CoreExpr -> [Var.Var] -> [Var.Var]
csceToVars' (Var var)   = (var:)
csceToVars' (App e0 e1) = csceToVars' e0 . csceToVars' e1
csceToVars' (Lam _ e)   = csceToVars' e
csceToVars' (Let (NonRec _ e0) e1) = csceToVars' e0 . csceToVars' e1
csceToVars' (Let (Rec tups) e)     = foldr (.) (csceToVars' e) [ csceToVars' a | (_,a) <- tups ]
csceToVars' (Case e _ _ tups)      = foldr (.) (csceToVars' e) [ csceToVars' a | (_,_,a) <- tups ]
csceToVars' (Cast e _)             = csceToVars' e
csceToVars' (Note _ e)             = csceToVars' e
csceToVars' _                      = id -- Lit case and Type case

-}


thExpToCSCE :: GlobalMap -> TH.Exp -> CoreSyn.CoreExpr
thExpToCSCE gm ce = ctc [] ce
    where ctc pvs (TH.LamE pvars e)       = foldr CoreSyn.Lam (ctc (pvars++pvs) e) (map (mkStrVar . show . unVarP) pvars)
          ctc pvs (e0 `TH.AppE` e1)       = ctc pvs e0 `CoreSyn.App` ctc pvs e1
          ctc pvs (InfixE (Just e0) e (Just e1)) = lup e `CoreSyn.App` ctc pvs e0 `CoreSyn.App` ctc pvs e1 
          ctc pvs (TH.VarE name) | VarP name `elem` pvs = CoreSyn.Var $ mkStrVar $ show name
          -- VarEの場合，lambda boundの場合と，globalの場合とで扱いが異なる．
          -- スコープをまじめに考えると，lambda boundかどうかをチェックしてからglobalにあるかどうかをみることになる． 
          ctc pvs e                       = lup e
          lup e = case Map.lookup (thToBaseString e) gm of Nothing   -> error (show e ++ ", i.e.,\n" ++ TH.pprint e ++ " : could not convert to CoreSyn.CoreExpr")
                                                           Just csce -> csce
thToBaseString (ConE name) = nameBase name
thToBaseString (VarE name) = nameBase name

unVarP (TH.VarP n) = n
mkIntVar i   = Id.mkUserLocal (mkVarOcc [chr i]) (Unique.getUnique i) anyPrimTy noSrcSpan
mkStrVar str = Id.mkUserLocal (mkVarOcc str) (Unique.getUnique $ mkFastString str) anyPrimTy noSrcSpan


type GlobalAr = Array Int CoreSyn.CoreExpr
mkGlobalAr :: HscEnv -> [(a, TH.Exp, TH.Type)] -> IO GlobalAr
mkGlobalAr hscEnv tups = do ces <- mapM (compileVar hscEnv) tups
                            return $ listArray (0, length tups - 1) ces

ceToCSCE :: GlobalAr -> CoreLang.CoreExpr -> CoreSyn.CoreExpr
ceToCSCE ga ce = ctc (ord 'a'-1) ce
    where ctc dep (CoreLang.Lambda e)       = CoreSyn.Lam  (mkIntVar (dep+1)) $ ctc (dep+1) e
          ctc dep (CoreLang.X n)            = CoreSyn.Var $ mkIntVar (dep-n)
          ctc dep (CoreLang.Primitive n)    = ga ! n
          ctc dep (e0 CoreLang.:$ e1)       = ctc dep e0 `CoreSyn.App` ctc dep e1




es = map mkIntVar [ord 'e'..]
as = map mkIntVar [128..] -- 無理がある?
xs = map mkIntVar [192..]
hd = mkIntVar (ord 'a')   -- これは引数にしても良い

mkTV :: Int -> Types.Type
mkTV = Types.TV
tvrs = map mkTV [1..]
tvas = map mkTV [2000..]
tvr  = mkTV 0

-- ({} \ hd e1..em a1..an -> {hd e1..em a1..an} let x1 = {e1 a1..an} e1 a1..an in {hd x1 e2..em a1..an} let x2 = {e2 a1..an} e2 a1..an in .. {hd x1..xm-1 em a1..an} let xm = {em a1..an} em a1..an in {hd x1..xm} hd x1..xm
-- てか，一番上がemptyVarSetであることを除けば，あとはundefinedでいいはず．... と思ったけど，schemeEの定義を見た感じlet bindingsの右辺の一番外側に関しては必要みたい．see notes on Aug. 12, 2008
-- ({} \ hd e1..em a1..an -> let x1 = {e1 a1..an} e1 a1..an in let x2 = {e2 a1..an} e2 a1..an in .. let xm = {em a1..an} em a1..an in hd x1..xm
-- という程度の情報があれば十分．

-- (\hd e1..em a1..an -> let x1 = e1 a1..an in .. let xm = em a1..an in hd x1..xm) :: (r1->..->rm->r) -> (a1->..->an->r1)->..->(a1->..->an->rm) -> a1->..->an -> r
hdmnPreped :: Int -> Int -> CoreSyn.CoreExpr
hdmnPreped m 0 = hdmn m 0 -- 要はidを生成するってこと．
hdmnPreped m n = lambdas $ lets $ foldl CoreSyn.App (CoreSyn.Var hd) (map CoreSyn.Var mxs)
    where
       mes = take m es
       mxs = take m xs
       nas = take n as
       lambdas = flip (foldr ($)) (map CoreSyn.Lam (hd : mes ++ nas))
       lets = flip (foldr CoreSyn.Let) binds 
           where binds = zipWith CoreSyn.NonRec mxs $ map appa1an mes
                     where appa1an var = foldl CoreSyn.App (CoreSyn.Var var) $ map CoreSyn.Var nas
-- CorePrep 前のものを生成する場合
-- (\hd e1..em a1..an -> hd (e1 a1..an) .. (em a1..an)) :: (r1->..->rm->r) -> (a1->..->an->r1)->..->(a1->..->an->rm) -> a1->..->an -> r
hdmn m n = lambdas $ foldl CoreSyn.App (CoreSyn.Var hd) $ map appa1an mes
 where appa1an var = foldl CoreSyn.App (CoreSyn.Var var) $ map CoreSyn.Var nas
       mes = take m es
       nas = take n as
       lambdas = flip (foldr ($)) (map CoreSyn.Lam (hd : mes ++ nas))

hdmnty :: Int -> Int -> Types.Type
hdmnty m n = hdty Types.:-> foldr (Types.:->) (foldr (Types.:->) tvr nas) (map (\r -> foldr (Types.:->) r nas) mrs)
    where hdty = foldr (Types.:->) tvr mrs
          mrs  = take m tvrs
          nas  = take n tvas


-- (\e1..em a1..an -> let x1 = e1 a1..an in .. let xm = em a1..an in ai x1 .. xm) -- more exactly, not ai but ai-1 because (!!) counts starting 0
--   :: (a1->..->(r1->..->rm->r)->..->an->r1)->..->(a1->..->(r1->..->rm->r)->..->an->rm) ->
--       a1->..->(r1->..->rm->r)->..->an -> r
-- aimnPreped i m 0 = aimn i m 0 -- これはありえないケース
aimnPreped i m n = lambdas $ foldl CoreSyn.App (CoreSyn.Var (as!!i)) (map CoreSyn.Var mxs)
 where mes = take m es
       mxs = take m xs
       nas = take n as
       lambdas = flip (foldr ($)) (map CoreSyn.Lam (mes ++ nas))
       lets = flip (foldr CoreSyn.Let) binds 
           where binds = zipWith CoreSyn.NonRec mxs $ map appa1an mes
                     where appa1an var = foldl CoreSyn.App (CoreSyn.Var var) $ map CoreSyn.Var nas
-- CorePrep前のものを生成する場合
-- (\e1..em a1..an -> ai (e1 a1..an) .. (em a1..an)) -- more exactly, not ai but ai-1 because (!!) counts starting 0
--   :: (a1->..->(r1->..->rm->r)->..->an->r1)->..->(a1->..->(r1->..->rm->r)->..->an->rm) ->
--       a1->..->(r1->..->rm->r)->..->an -> r
aimn i m n = lambdas $ foldl CoreSyn.App (CoreSyn.Var (as!!i)) $ map appa1an mes
 where appa1an var = foldl CoreSyn.App (CoreSyn.Var var) $ map CoreSyn.Var nas
       mes = take m es
       nas = take n as
       lambdas = flip (foldr ($)) (map CoreSyn.Lam (mes ++ nas))

aimnty :: Int -> Int -> Int -> Types.Type
aimnty i m n = foldr (Types.:->) (foldr (Types.:->) tvr nas) (map (\r -> foldr (Types.:->) r nas) mrs)
    where hdty = foldr (Types.:->) tvr mrs
          mrs  = take m tvrs
          nas  = case splitAt i tvas of (tk,_:dr) -> tk ++ hdty : take (n-i-1) dr -- hdmntyとの違いはここだけ

mkHdmn :: HscEnv -> Int -> Int -> IO Dynamic
mkHdmn hscEnv m n =  do let ce = hdmn m n
                        val <- runCoreExpr hscEnv ce
                        return $ unsafeToDyn undefined (hdmnty m n) val undefined -- (CoreLang.exprToTHExp undefined ce) CoreLangではなくてCoreSynから
mkAimn :: HscEnv -> Int -> Int -> Int -> IO Dynamic
mkAimn hscEnv i m n =  do let ce = aimn i m n
                          val <- runCoreExpr hscEnv ce
                          return $ unsafeToDyn undefined (aimnty i m n) val undefined -- (CoreLang.exprToTHExp undefined ce)
#endif
-- ifdef GHC6

-- こっからプロファイル用


repeatN  n f x = force $ map f $ replicate n x
repeatIO n act = fmap force $ sequence $ replicate n act

-- force (x:xs) = all (x==) xs `seq` x
force = foldr1 seq

instance Eq (Expr a) where
    Var i == Var j = True -- i==j
    Lit l == Lit m = l==m
    App f e == App g i = g==f && e==i
    Lam b e == Lam c f = {- b==c && -} e==f
    Let b e == Let c f = {- b==c && -} e==f
    Case e b t ab == Case f c u bc = e==f {- && b==c && t==u && ab == bc -}
    Cast e c      == Cast f d = e==f {- && c==d -}
    Note n e == Note m f = {- n==m && -} e==f
    Type t == Type u = True -- t==u



