> {-# OPTIONS_GHC -fglasgow-exts #-}

> module Ivor.Compiler(compile) where

> import Ivor.RunTT
> import Ivor.State
> import Ivor.Nobby
> import Ivor.Datatype
> import Ivor.TTCore
> import Ivor.ICompile

> import System.IO
> import Control.Monad

> compile :: IState -> String -> IO ()
> compile st froot = fail "Deprecated"


>  {-   do h <- openFile (froot++".hs") WriteMode
>        hPutStr h (header froot)
>        compileData (defs st) (datadefs st) st h
>        compileGamma (defs st) st h
>        hFlush h
>        hClose h

FIXME! Only does elim, not case.

> compileData :: Gamma Name -> [(Name,Datatype Name)] -> IState ->
>                Handle -> IO ()
> compileData gam [] st h = return ()
> compileData gam ((n,dt):xs) st h =
>     do let caseexp = compileSchemes (e_ischemes dt)
>        let arity = getArity (e_ischemes dt)
>        rn <- rulename
>        if (length (datacons dt)>0) then
>           hPutStrLn h $ "data TT_" ++ exportName n ++ " = " ++ compileCons (datacons dt)
>           else hPutStrLn h $ "data TT_" ++ exportName n ++ " = TT_" ++ exportName n
>        let inst = projInstance (datacons dt)
>        when ((length (words inst))>0)
>           $ hPutStrLn h $ "\ninstance Project TT_"++ exportName n ++
>                 " where\n" ++ inst
>        let rtt = mkRTElim n arity caseexp
>        let fn = mkGHC st rn arity rtt
>        hPutStrLn h fn
>        --putStrLn $ elimInterface n (snd (erule dt))
>        --putStrLn $ elimBody n rn (snd (erule dt))
>        --hPutStrLn h $ show rtt
>        compileData gam xs st h
>  where rulename = case lookupval n gam of
>                      (Just (TCon _ (Elims x _ _))) -> return x
>                      Nothing -> fail "No such type"

This creation of elim rule interfaces only works for completely simple types!

> elimInterface :: Name -> Indexed Name -> String
> elimInterface n (Ind ty) = "elim_" ++ exportName n ++ " :: " ++ mkET ty
>    where mkET (Bind _ (B Pi ty) (Sc sc)) = mkArg ty ++ mkET sc
>          mkET _ = "a"
>          mkArg ty | Star <- getReturnType ty = "" -- Skip Phi
>                   | TyCon x _ <- getFun ty
>                        = "TT_" ++ exportName x ++ " -> "
>                   | otherwise = "(" ++ mkET ty ++ ") -> "

> elimBody :: Name -> Name -> Indexed Name -> String
> elimBody n rn (Ind ty) = "elim_" ++ exportName n ++ " = " ++ mkLams ty 0 ++
>                          "(coerce (fn_" ++ exportName rn ++ " " ++ mkET ty 0
>                          ++ "))::a"
>    where
>          mkET (Bind _ (B Pi ty) (Sc sc)) n | Star <- getReturnType ty
>                                                = mkArg ty n ++ mkET sc n
>          mkET (Bind _ (B Pi ty) (Sc sc)) n = mkArg ty n ++ mkET sc (n+1)
>          mkET _ _ = ""
>          mkLams (Bind _ (B Pi ty) (Sc sc)) n | Star <- getReturnType ty
>                                                = mkLams sc n
>          mkLams (Bind _ (B Pi ty) (Sc sc)) n = "\\x"++show n ++ " -> "
>                                                ++ mkLams sc (n+1)
>          mkLams _ _ = ""

>          mkArg ty n | Star <- getReturnType ty = "((coerce Type)::val)"
>                     | otherwise = "((coerce x"++show n++")::val)"

> compileCons :: [(Name,Gval Name)] -> String
> compileCons [] = ""
> compileCons [x] = compileCon x
> compileCons (x:xs) = compileCon x ++ "| " ++ compileCons xs

> compileCon (n,G (DCon _ _) (Ind t) _) =
>     foralls numargs ++ "TT_" ++ show n ++ " " ++ showargs numargs
>   where numargs = length (getExpected t)
>         foralls n | n == 0 = ""
>                   | otherwise = "forall arg. "
>         showargs 0 = ""
>         showargs n = "arg " ++ showargs (n-1)

> projInstance :: [(Name,Gval Name)] -> String
> projInstance [] = ""
> projInstance (x:xs) =
>     let xp = projAll x in
>        if (length (words xp)>0) then xp ++ "\n" ++ projInstance xs
>           else projInstance xs

> projAll (n,G (DCon _ _) (Ind t) _) =
>     project numargs
>   where numargs = length (getExpected t)
>         project 0 = "\n"
>         project k = "    project "++show (k-1)++" (TT_" ++ exportName n ++
>                     " " ++ showargs numargs++") = ((coerce a" ++ show (k-1)
>                         ++ ")::val)\n" ++ project (k-1)
>         showargs 0 = ""
>         showargs n = showargs (n-1) ++ " a" ++ show (n-1)

> compileGamma :: Gamma Name -> IState -> Handle -> IO ()
> compileGamma gam@(Gam g) st h = cg g where
>   cg [] = return ()
>   cg ((n,G (Fun _ ind) indty _):xs) =
>       do -- putStrLn $ "Compiling " ++ show n
>          let nind = normalise (Gam []) ind
>          let rtt = mkRTFun gam (levelise nind)
>          let (Ind ty) = normalise gam indty
>          let arity = length (getExpected ty)
>          let fn = mkGHC st n arity rtt
>          hPutStrLn h fn
>          cg xs
>   cg (x:xs) = do -- putStrLn $ "Skipping " ++ show x
>                  cg xs

> mkGHC :: IState -> Name -> Int -> RunTT -> String
> mkGHC st n arity tm = "fn_" ++ exportName n ++ " :: " ++ mkSig arity ++ "\n" ++
>                       "fn_" ++ exportName n ++ " = " ++ mkBody 0 tm ++ "\n"
>    where mkSig 0 = "val"
>          mkSig n = "val -> " ++ mkSig (n-1)
>          mkBody l (RTVar i) = "v"++show i
>          mkBody l (RTFun n) = "fn_" ++ exportName n
>          mkBody l (RTCon _ n args) = "(coerce (TT_" ++ exportName n ++ " " ++ showargs l args ++ ")::val)"
>          mkBody l (RTElim n t m ms) = "(fn_" ++ exportName n ++ " " ++ showarg l t ++
>                                     " ((coerce Type)::val) " ++ showargs l ms
>          mkBody l (RTApp f xs) = "(" ++ showfun l f (length xs) ++ " " ++ showargs l xs ++ ")"
>          mkBody l (RTBind (RTLam,_) (sc,_)) = "(\\v"++show l ++" -> " ++ mkBody (l+1) sc ++ ")"
>          mkBody l (RTBind (RTLet (v,_),_) (sc,_)) = "(let v"++show l ++" = " ++ "(" ++ mkBody l v ++ ") in (" ++ mkBody (l+1) sc ++ "))"
>          mkBody l (RTBind (RTPi,_) (sc,_)) = "((coerce Type)::val)"
>          mkBody l RTypeVal = "((coerce Type)::val)"
>          mkBody l RTCantHappen = "error \"Impossible\""
>          mkBody l (RTProj ty i (v,_)) = "(project " ++ show i ++
>                                      "((coerce " ++ mkBody l v ++")::TT_"++show ty++"))"
>          mkBody l (RTCase ty (v,_) xs) = "(case ((coerce "++mkBody l v++")::TT_"++show ty++") of { " ++ doCaseBody l (getCons (datadefs st) ty) xs ++ "})"
>          mkBody l (RTConst c) = error "Sorry, can't compile constants yet"
>          -- mkBody l x = "[[Not done "++show x++"]]"

>          doCaseBody l [] [] = ""
>          doCaseBody l ((n,ar):ns) (i:is) = doCase l n ar i ++ " ; " ++ doCaseBody l ns is
>          doCase l n ar (i,_) = "TT_"++exportName n++" "++caseargs ar++" -> " ++ mkBody l i
>          caseargs 0 = ""
>          caseargs n = "_ "++caseargs (n-1)

>          showargs l [] = ""
>          showargs l (x:xs) = showarg l x ++ " " ++ showargs l xs
>          showarg l (x,_) = "((coerce "++mkBody l x++")::val)"
>          showfun l (f,_) n = "((coerce "++mkBody l f++")::"++mkty n++")"

>          mkty 0 = "val"
>          mkty n = "val->"++mkty (n-1)

Given a type name, get all the constructors and their arities

> getCons :: [(Name,Datatype Name)] -> Name -> [(Name,Int)]
> getCons ds n = case lookup n ds of
>                  Nothing -> []
>                  Just dt -> map (\ (x,y) -> (x, arity y)) (datacons dt)
>     where arity (G _ (Ind ty) _) = length (getExpected ty)

> header mod = "{-# OPTIONS_GHC -fglasgow-exts #-} \n\
>               \\n\
>               \module " ++ mod ++ " where\n\
>               \\n\
>               \import GHC.Base\n\
>               \\n\
>               \coerce :: a -> b\n\
>               \coerce = unsafeCoerce#\n\
>               \\n\
>               \data Type = forall a. Type a\n\
>               \data Val = Val\n\
>               \\n\
>               \class Project x where\n\
>               \    project :: forall val. Int -> x -> val\n\n"

> exportName :: Name -> String
> exportName (UN n) = show $ UN (okch n)
>    where okch [] = []
>          okch ('\'':xs) = "_AP_"++okch xs
>          okch (x:xs) = x:(okch xs)
> -}