pec-0.1: Main.hs
{-# OPTIONS -Wall -fno-warn-name-shadowing #-}
{-# LANGUAGE DeriveDataTypeable #-}
-- The pec embedded compiler
-- Copyright 2011, Brett Letner
module Main (main) where
import Control.Monad.State
import Data.Char
import Data.Either
import Data.List
import GHC.IO.Exception
import Language.Pec.Abs
import Language.Pec.ErrM
import Language.Pec.Layout
import Language.Pec.Par
import Language.Pec.Print
import System.Console.CmdArgs
import System.Directory
import System.FilePath
import System.Process
import qualified Language.Haskell as H
data Args = Args
{ files :: [FilePath]
, keep_tmp_files :: Bool
, rebuild_all :: Bool
} deriving (Show, Data, Typeable)
argsDesc :: Args
argsDesc = Args
{ files = def &= args
, keep_tmp_files = def &= help "Keep temporary files"
, rebuild_all = def &= help "Rebuild all files"
} &= summary summry &= program prog
summry :: String
summry = prog ++ " v" ++ vers ++ ", " ++ copyright
prog :: String
prog = "pec"
copyright :: String
copyright = "(C) Brett Letner 2011"
vers :: String
vers = "0.1"
initSt :: Args -> St
initSt x = St
{ visited = []
, modified = False
, rebuild = rebuild_all x
, not_visited = map (\fn -> dropExtension fn ++ "_") $ files x
, strings = []
, counts = []
, keep_tmps = keep_tmp_files x
-- , mains = []
}
type M a = StateT St IO a
data St = St
{ not_visited :: [FilePath]
, modified :: Bool
, rebuild :: Bool
, visited :: [FilePath]
, strings :: [String]
, counts :: [Integer]
, keep_tmps :: Bool
-- , mains :: [FilePath]
}
main :: IO ()
main = do
args <- cmdArgs argsDesc
let fns = files args
case fns of
[] -> putStrLn summry
(fn:_) -> do
let mnFn = new_ext "_main.hs" fn
let llFn = new_ext ".ll" fn
st <- execStateT pec_all $ initSt args
when (modified st || rebuild st) $ writeFile mnFn $ H.prettyPrint $
hMainModule (dropExtension fn) (visited st) (strings st)
let mnExe = new_ext ".exe" mnFn
my_system $ unwords ["ghc --make -o", mnExe, mnFn] -- fixme:check exit code
pwd <- getCurrentDirectory
my_system $ pwd ++ "/" ++ mnExe
let llFns = ["istrings_" ++ new_ext ".ll" fn] ++ (map (new_ext ".ll" . init) $ visited st)
let llBc = new_ext ".bc" llFn
my_system $ "cat " ++ unwords llFns ++ " | llvm-as > " ++ llBc
let llExe = new_ext ".exe" llFn
my_system $ unwords ["llvm-ld -disable-opt -o", llExe, llBc] -- array bug in llvm
when (not $ keep_tmps st) $ my_system $ unwords $
[ "rm *.hi *.o", "*_.hs" -- fixme: clean up Cnts files
, mnExe, mnFn, llBc
] ++ llFns
return ()
pec_all :: M ()
pec_all = do
st <- get
case not_visited st of
[] -> return ()
(n:ns) -> do
put $ st{ not_visited = ns }
when (n `notElem` visited st) $ do
ns <- pec_file n
modify $ \st -> st{ visited = n : visited st
, not_visited = ns ++ not_visited st
}
pec_all
pec_file :: FilePath -> M [FilePath]
pec_file n = do
let fn = init n ++ ".pec"
let hsFn = new_ext "_.hs" fn
ss <- lift $ liftM lines $ readFile fn
let (xs,ys) = partition (\s -> not (null s) && head s == '>') ss
case pModule $ resolveLayout True $ myLexer $ unlines ys of
Bad e -> error e
Ok m -> do
b <- isOutOfDate fn hsFn
h <- hModule m
when b $ do
modify $ \st -> st{ modified = True }
lift $ writeFile hsFn $ unlines $
imports_hack (lines $ H.prettyPrint h) (map tail xs)
return $ imports m
isOutOfDate :: FilePath -> FilePath -> M Bool
isOutOfDate inFn outFn = do
b <- gets rebuild
if b
then return True
else do
r <- lift $ doesFileExist outFn
if r
then liftM2 (>) (lift $ getModificationTime inFn) (lift $ getModificationTime outFn)
else return True
imports_hack :: [String] -> [String] -> [String]
imports_hack xs ys
| null es = bs ++ cs ++ ds
| otherwise = bs ++ ds ++ fs ++ cs ++ gs
where
(bs,cs) = break (has_prefix "import ") xs
(ds,es) = break (has_prefix "import ") ys
(fs,gs) = span (has_prefix "import ") es
doList :: [H.Exp] -> H.Exp
doList xs =
H.Do $ map H.Qualifier $ xs ++ [H.apps (H.var "return") [H.Tuple []]]
importDecl :: Bool -> String -> H.ImportDecl
importDecl q n = H.ImportDecl
{ H.importModule = H.ModuleName n
, H.importQualified = q
, H.importLoc = nl
, H.importSrc = False
, H.importPkg = Nothing
, H.importAs = Nothing
, H.importSpecs = Nothing
}
typeSig :: String -> H.Type -> H.Decl
typeSig s = H.TypeSig nl [H.name s]
gen :: Modid -> [TopDecl] -> [H.Decl]
gen n xs =
[ typeSig "gen" $ H.TyApp (H.tyCon "M") (H.TyTuple H.Boxed [])
, H.bind "gen" [] $ H.apps (H.var "gen_file") [H.strE $ printTree n, doList $ concatMap f xs ]
]
where
f x = case x of
ExternD _ a _ -> [H.apps (H.var "declare") [hvar a "d"]]
ProcD a _ _ -> [H.apps (H.var "define") [hvar a "d"]]
_ -> []
hmodule :: String -> [String] -> Maybe [H.ExportSpec] -> [H.ImportDecl] -> [H.Decl] -> H.Module
hmodule n ps = H.Module nl (H.ModuleName n)
[H.LanguagePragma nl [H.name p] | p <- ps ] Nothing
hMainModule :: FilePath -> [String] -> [String] -> H.Module
hMainModule fn ns ss = hmodule "Main" [] Nothing imps [mainDecl]
where
imps = importDecl False "Pec.Base" : map (importDecl True) ns
mainDecl = H.bind "main" [] $ H.apps (H.var "gen_files")
[ H.strE fn
, doList [H.qvar (H.ModuleName n) (H.name "gen") | n <- ns ]
, H.List $ map H.strE $ nub $ sort ss
]
filterCnts :: (Ord a, Num a) => [a] -> [a]
filterCnts xs = filter (`notElem` [256, 4294967296]) $ nub $ sort xs
hCountModule :: Integer -> M ()
hCountModule i = do
q <- gets rebuild
r <- lift $ doesFileExist fn
when (q || not r) $ do
modify $ \st -> st{ modified = True }
lift $ writeFile fn $ H.prettyPrint $ hmodule n [] Nothing
[importDecl False "Pec.Base"]
[ hdatadecl n [] [H.QualConDecl nl [] [] (H.ConDecl (H.name n) [])]
, hinstdecl [] "Count" [H.tyCon n]
[H.InsDecl $ H.simpleFun nl (H.name "countof") (H.name "_") (H.intE i)]
, hinstdecl [] "Typed" [H.tyCon n]
[H.InsDecl $ H.simpleFun nl (H.name "typeof") (H.name "_") (H.con "TyUnit")]
]
where
n = "Cnt" ++ show i
fn = n ++ ".hs"
hinstdecl :: H.Context -> String -> [H.Type] -> [H.InstDecl] -> H.Decl
hinstdecl qs n = H.InstDecl nl (nub $ sort qs) (H.qname n)
hModule :: Module -> M H.Module
hModule (Module a b cs) = do
(xs,ys) <- liftM partitionEithers $ mapM (hTopDecl n) cs
cnts <- liftM filterCnts $ gets counts
modify $ \st -> st{ counts = [] }
mapM_ hCountModule cnts
return $ hmodule n
[ "FlexibleInstances", "MultiParamTypeClasses", "ScopedTypeVariables"
, "TypeSynonymInstances" ]
(hExpDecl a cs b)
(importDecl False "Pec.Base" : [ importDecl False $ "Cnt" ++ show cnt | cnt <- cnts ] ++ xs)
(gen a cs ++ concat ys)
where n = userc a
hExpDecl :: Modid -> [TopDecl] -> ExportDecl -> Maybe [H.ExportSpec]
hExpDecl n xs a = case a of
ExpAllD -> Nothing
ExpListD bs -> Just $ (H.EVar $ H.Qual (H.ModuleName $ userc n) (H.name "gen")) : concatMap (hExport xs) bs
hevar :: String -> H.ExportSpec
hevar = H.EVar . H.qname
hExport :: [TopDecl] -> Export -> [H.ExportSpec]
hExport xs ex = case ex of
VarEx a -> [hevar $ user a]
TypeEx a b -> H.EThingWith (H.qname $ userc a) [] : map hevar zs
where
zs = case (lookupType xs a, b) of
(_, Neither) -> []
(TyTagged ys, Decon) -> concat $ map (tail . nPat) ys
(TyTagged ys, Both) -> concatMap nPat ys
(TyRecord ys, Both) -> map hgetfld ys
_ -> error "export spec doesn't match type decl"
lookupType :: Print a => [TopDecl] -> a -> TyDecl
lookupType xs a = case [ b | TypeD a1 _ b <- xs, printTree a == printTree a1 ] of
[] -> error $ "unknown type decl:" ++ printTree a
(b:_) -> b
hTopDecl :: String -> TopDecl -> M (Either H.ImportDecl [H.Decl])
hTopDecl qn x = case x of
VarD a b -> do
e <- hExp b
return $ Right [ nameBind (user a) e ]
ProcD a bs c -> do
e0 <- hExp c
e1 <- foldM hArg e0 $ reverse bs
return $ Right
[ nameBind n $ H.App (H.var "call") (H.var nd)
, nameBind nd $ H.apps (H.var "proc")
[ H.strE $ init $ if n == "main_" then n else qn ++ "." ++ n
, e1
]
]
where
n = user a
nd = n ++ "d"
ImportD a b -> case b of
AsAS{} -> error "todo:'import as' not implemented"
EmptyAS -> return $ Left $ importDecl False (userc a)
ExternD a b c -> do
t <- htype "Decl" c
return $ Right
[ nameBind (user b) $ H.App (H.var "call") (H.var nd)
, nameBind nd $ ascribe (H.App (H.var "extern") (H.strE s)) t
]
where
s = case a of
NoneNm -> printTree b
SomeNm s -> s
nd = user b ++ "d"
AscribeD a b -> do
t <- htype "Term" b
return $ Right [typeSig (user a) t]
TypeD a bs0 c -> do
let bs = map uTyVar bs0
let t0 = dtype_ty a bs
case c of
TySyn d -> do
t <- pType d
return $ Right
[H.TypeDecl nl (H.name $ userc a) (map htvbind bs) t]
TyRecord fs0 -> do
let fs = sortBy cmpFieldT fs0
Right ds <- hTopDecl qn $ TypeD a bs0 $ TyTagged [ConC a [ t | FieldT _ t <- fs ]]
xs <- mapM (hfieldt t0 bs $ length fs) $ zip fs [0 .. ]
return $ Right $ concat xs ++ ds
TyTagged xs0 -> do
let xs = sortBy (\(ConC a _) (ConC b _) -> compare a b) xs0
let cnt = genericLength xs
add_count cnt
let dd = hdatadecl (userc a) (map htvbind bs) []
cts <- sequence [ htytuple ts | ConC _ ts <- xs ]
let rs = concatMap (fconc a bs cnt (isTyEnum xs)) $ zip (zip xs [0 .. ]) cts
let typed_id e = hinstdecl (pre bs) "Typed" [t0] [ H.InsDecl $ nameBind "typeof" $ H.lamE nl [H.PParen $ H.PatTypeSig nl (H.PWildCard) t0 ] e ]
return $ Right $ case () of
() | isTyUnit xs ->
let
[ConC m _] = xs
n = user m
in
[ dd
, typed_id $ H.con "TyUnit"
, typeSig n $ tpred bs $ tterm t0
, nameBind n $ H.App (H.var "cast") (H.var "unit")
, hinstdecl (hassts "EQ" bs) "EQ" [t0]
[ H.InsDecl $ nameBind "eq" (H.var "eq_unit")
, H.InsDecl $ nameBind "ne" (H.var "ne_unit") ]
]
| isTyNewtype xs ->
let
[ct] = cts
[ConC m _] = xs
n = user m
in
[ dd
, typed_id $ unused_ty ct
, hinstdecl (hassts "Typed" bs) "Newtype" [t0, ct] []
-- , hinstdecl (hassts "EQ" bs) "EQ" [t0]
-- [ H.InsDecl $ nameBind "eq" (H.App (H.var "unwrap2") (H.var "eq"))
-- , H.InsDecl $ nameBind "ne" (H.App (H.var "unwrap2") (H.var "ne")) ]
, typeSig n $ tpred bs $ tterm $ H.TyFun ct t0
, nameBind n $ H.var "wrap"
]
| isTyEnum xs ->
[ dd
, typed_id $ H.App (H.con "TyEnum") (H.intE cnt)
, hinstdecl (pre bs) "Tagged" [ t0, tcnt cnt ]
[H.InsDecl $ nameBind "tagof" (H.var "cast")]
, hinstdecl [] "EQ" [t0] []
] ++ rs
| otherwise ->
[ dd
, typed_id $ H.App (H.con "TySum") (H.List [unused_ty ct | ct <- cts ])
, hinstdecl (pre bs) "Tagged" [ tptr t0, tcnt cnt ]
[H.InsDecl $ nameBind "tagof" (H.var "tagofp")]
] ++ rs
hfieldt :: H.Type -> [TyVar] -> Int -> (FieldT, Int) -> M [H.Decl]
hfieldt t0 tvs cnt (fld@(FieldT _ t), i) = do
ht <- pType t
return
[ typeSig n $ tpred tvs $ H.TyFun (tterm $ tptr t0) (tterm $ tptr ht)
, nameBind n $ foldr (\a b -> H.InfixApp (H.var $ a ++ "_get") (H.qvop ".") b) (H.App (H.var "app") (H.var "unwrap_ptr_")) ss
]
where
n = hgetfld fld
ss = case cnt of
1 -> []
_ | i == cnt - 1 -> replicate i "snd"
_ -> ["fst"] ++ replicate i "snd"
hgetfld :: FieldT -> String
hgetfld (FieldT f _) = user f ++ "get"
cmpFieldT :: FieldT -> FieldT -> Ordering
cmpFieldT (FieldT a _) (FieldT b _) = compare a b
cmpFieldD :: FieldD -> FieldD -> Ordering
cmpFieldD (FieldD a _) (FieldD b _) = compare a b
unused_ty :: H.Type -> H.Exp
unused_ty t = H.App (H.var "typeof") $ ascribe (H.var "unused") t
isTyUnit :: [ConC] -> Bool
isTyUnit x = isTyNewtype x && isTyEnum x
isTyNewtype :: [a] -> Bool
isTyNewtype [_] = True
isTyNewtype _ = False
isTyEnum :: [ConC] -> Bool
isTyEnum xs = and [ null ys | ConC _ ys <- xs ]
hdatadecl :: String -> [H.TyVarBind] -> [H.QualConDecl] -> H.Decl
hdatadecl n vs ds = H.DataDecl nl H.DataType [] (H.name n) vs ds []
htycon :: Print a => a -> H.Type
htycon = H.tyCon . userc
htyvar :: TyVar -> H.Type
htyvar = H.tyVar . printTree . uncnttv
uncnttv :: TyVar -> Lident
uncnttv x = case x of
CntTV a -> a
VarTV a -> a
uTyVar :: TyVar -> TyVar
uTyVar x = case x of
CntTV a -> CntTV $ Lident $ user a
VarTV a -> VarTV $ Lident $ user a
pre :: [TyVar] -> [H.Asst]
pre = map hasst
hasst :: TyVar -> H.Asst
hasst x = case x of
CntTV{} -> H.ClassA (H.qname "Count") [htyvar x]
VarTV{} -> H.ClassA (H.qname "Typed") [htyvar x]
hassts :: String -> [TyVar] -> [H.Asst]
hassts s tvs = [H.ClassA (H.qname s) [htyvar tv] | tv@VarTV{} <- tvs ] ++ map hasst tvs
dtype_ty :: Print a => a -> [TyVar] -> H.Type
dtype_ty a tvs = H.tyApps (htycon a) $ map htyvar tvs
tptr :: H.Type -> H.Type
tptr = H.TyApp (H.tyCon "Ptr")
tcnt :: Show a => a -> H.Type
tcnt cnt = H.tyCon $ "Cnt" ++ show cnt
tpred :: [TyVar] -> H.Type -> H.Type
tpred xs = H.TyForall Nothing (pre xs)
tterm :: H.Type -> H.Type
tterm = H.TyApp (H.tyCon "Term")
fconc :: (Print a, Show a1) =>
a
-> [TyVar]
-> a1
-> Bool
-> ((ConC, Integer), H.Type)
-> [H.Decl]
fconc a tvs cnt is_enm ((conc@(ConC _ ts), i),t1) =
[ typeSig nTag $ tpred tvs $ tterm $ H.tyApps (H.tyCon "Tag") [mtptr t0, tcnt cnt]
, nameBind nTag $ H.App (H.var "tag") (H.intE i)
, typeSig n $ tpred tvs $ tterm $ if null ts then t0 else H.TyFun t1 t0
, nameBind n $ H.App (H.var $ if is_enm then "cast" else if null ts then "constr0" else "constr") (H.var nTag)
, typeSig nAlt $ tpred ((VarTV $ Lident "a") : tvs) $ H.TyFun (H.TyFun (tterm (mtptr t1)) (tterm ta)) $ H.TyFun (tterm (mtptr t0)) (tterm ta)
, nameBind nAlt $ H.var $ if is_enm then "alt0" else "alt"
]
where
t0 = dtype_ty a tvs
[n, nTag, nAlt] = nPat conc
ta = H.tyVar "a"
mtptr v = if is_enm then v else tptr v
nPat :: ConC -> [String]
nPat (ConC c _) = [n, n ++ "tag", n ++ "alt"]
where
n = user c
hArg :: H.Exp -> Exp -> M H.Exp
hArg e x = case x of
VarE{} -> return $ H.apps (H.var "arg")
[H.strE (printTree x), lambda [hpvar x] e]
TupleE [] -> return $ H.App (H.var "unitarg") e
TupleE [a] -> hArg e a
_ -> do
let v = varE "v"
s <- hStmt $ LetS x v
hArg (blocke [s, [H.Qualifier $ eval e]]) v
ascribe :: H.Exp -> H.Type -> H.Exp
ascribe a b = H.Paren $ H.ExpTypeSig nl a b
nameBind :: String -> H.Exp -> H.Decl
nameBind s = H.nameBind nl (H.name s)
htype :: String -> Type -> M H.Type
htype s = liftM (H.TyApp (H.tyCon s)) . pType
pType :: Type -> M H.Type
pType x = case x of
TyConstr0{} -> return $ htycon x
TyFun a b -> liftM2 H.TyFun (pType a) (pType b)
TyTuple xs -> htytuple xs
TyConstr a bs -> liftM (H.tyApps (htycon a)) $ mapM pType bs
TyArray a b -> liftM (H.tyApps (H.tyCon "Array")) $ mapM pType [a,b]
TyCount a -> add_count i >> return (tcnt i)
where i = pcount a
TyVarT a -> return $ H.tyVar $ user a
htytuple :: [Type] -> M H.Type
htytuple xs0 = case xs0 of
[] -> return $ tytuple []
[a] -> pType a
[a,b] -> liftM tytuple $ mapM pType [a,b]
(x:xs) -> liftM tytuple $ mapM pType [x, TyTuple xs]
htvbind :: TyVar -> H.TyVarBind
htvbind = H.UnkindedVar . H.name . printTree . uncnttv
pcount :: Count -> Integer
pcount = read . tail . printTree
tytuple :: [H.Type] -> H.Type
tytuple = H.TyTuple H.Boxed
lambda :: [H.Pat] -> H.Exp -> H.Exp
lambda = H.Lambda nl
hpvar :: Print a => a -> H.Pat
hpvar = H.pVar . user
hvar :: Print a => a -> String -> H.Exp
hvar a s = H.var $ user a ++ s
hCaseAlt :: CaseAlt -> M H.Exp
hCaseAlt (CaseAlt p x) = do
e <- hExp x
case p of
VarP{} -> return $ H.tuple [ H.var "defaulttag", lambda [hpvar p] e]
ConP a b -> return $ H.tuple
[ H.var $ s ++ "tag"
, H.App (H.var $ s ++ "alt") (lambda [hpvar b] e)
]
where s = user a
LitP y -> case y of
EnumL a -> hCaseAlt (CaseAlt (ConP a (var "_")) x)
IntL a -> f "int" (H.Paren $ H.Lit $ H.Int $ read $ printTree a)
StringL a -> add_string a >> f "string" (H.Lit $ H.String a)
CharL a -> f "char" (H.Lit $ H.Char a)
FracL{} -> error $ "can't case on fractional:" ++ printTree y
where
f s t = return $ H.tuple [ H.App (H.var $ s ++ "tag") t
, lambda [H.wildcard] e]
eval :: H.Exp -> H.Exp
eval e = H.App (H.var "eval") e
hStmt :: Exp -> M [H.Stmt]
hStmt x = case x of
LetS a b -> case a of
VarE{} -> do
e <- hExp b
return [H.Generator nl (hpvar a) $ eval e]
TupleE xs0 -> case xs0 of
[] -> do
e <- hExp b
t <- htype "Term" $ TyTuple []
return [H.Qualifier $ eval $ ascribe e t]
[e] -> hStmt $ LetS e b
[ea,eb] -> liftM concat $ mapM hStmt
[ LetS e b
, LetS ea $ AppE (varE "fst") e
, LetS eb $ AppE (varE "snd") e
] where e = varE "pat"
(x:xs) -> hStmt $ LetS (TupleE [x, TupleE xs]) b
AscribeE e t -> hStmt $ LetS e $ AscribeE b t
_ -> error $ "unexpected pattern:" ++ printTree x
_ -> do
e <- hExp x
return [H.Qualifier $ eval e]
varE :: String -> Exp
varE = VarE . var
var :: String -> Var
var = Var . Lident
con :: String -> Con
con = Con . Uident
blocke :: [[H.Stmt]] -> H.Exp
blocke = H.App (H.var "lift") . H.Do . concat
enuml :: String -> Lit
enuml = EnumL . con
penum :: String -> CasePat
penum = LitP . enuml
hExp :: Exp -> M H.Exp
hExp x = case x of
RecordE xs -> hExp $ BlockE $
[ LetS p $ varE "alloca'" ] ++
[ StoreE (FldE p a) b | FieldD a b <- sortBy cmpFieldD xs ] ++
[ UnOpE Load p ]
where p = varE "p"
BlockE xs -> liftM blocke $ mapM hStmt xs
LetS{} -> error "let stmt must be inside of do block"
LetE a b c -> hExp $ BlockE [LetS a b, c]
BranchE bs0 -> case bs0 of
(BranchAlt (BoolBP f) g : bs) | not $ null bs -> hExp $ CaseE f
[ CaseAlt (penum "True") g
, CaseAlt (penum "False") $ BranchE bs
]
[BranchAlt DefaultBP g] -> hExp g
_ -> error "malformed branch expression"
CaseE a bs -> do
e <- hExp a
cs <- mapM hCaseAlt bs
return $ H.apps (H.var "switch") [ e, H.List cs ]
StoreE a b -> do
ea <- hExp a
eb <- hExp b
return $ H.apps (H.var "store") [ea, eb]
AppE a b -> do
ea <- hExp a
eb <- hExp b
return $ H.apps (H.var "app") [ea, eb]
BinOpE a b c -> do
ea <- hExp a
ec <- hExp c
return $ H.Paren $ H.InfixApp ea (H.qvop $ eSym $ printTree b) ec
UnOpE a b ->
liftM (H.App (H.Paren $ H.var $ eSym $ printTree a)) $ hExp b
IdxE a b -> do
ea <- hExp a
eb <- hExp b
return $ H.apps (H.var "idx") [ea,eb]
FldE a b -> liftM (H.App (hvar b "get")) $ hExp a
ArrayE xs -> do
e <- hExp $ CountE (Count $ '#' : show (length xs))
es <- mapM hExp xs
return $ H.apps (H.var "array") [ e, H.List es ]
TupleE xs0 -> case xs0 of
[] -> return $ H.var "unit"
[a] -> hExp a
[a,b] -> do
ea <- hExp a
eb <- hExp b
return $ H.apps (H.var "pair") [ea,eb]
(x:xs) -> hExp $ TupleE [x, TupleE xs]
AscribeE a b -> liftM2 ascribe (hExp a) (htype "Term" b)
CountE a -> do
add_count i
return $ ascribe (H.var "unused") $
H.TyApp (H.tyCon "Term") (H.tyCon $ "Cnt" ++ show i)
where i = pcount a
VarE a -> return $ hvar a ""
LitE a -> hLit a
nl :: H.SrcLoc
nl = error "SRCLOC"
add_string :: String -> M ()
add_string s = modify $ \st -> st{ strings = s : strings st }
add_count :: Integer -> M ()
add_count s = modify $ \st -> st{ counts = s : counts st }
eSym :: String -> String
eSym cs = cs ++ "$"
hLit :: Lit -> M H.Exp
hLit x = case x of
EnumL a -> return $ H.var $ user a
CharL a -> return $ H.App (H.var "char") $ H.Lit $ H.Char a
IntL a -> return $ H.App (H.var "int") $ H.Paren $ H.Lit $ H.Int $ read $ printTree a
StringL a -> do
add_string a
return (H.App (H.var "string") $ H.Lit $ H.String a)
FracL a -> return $ H.App (H.var "frac") $ H.Paren $ H.Lit $ H.Frac $ toRational $ ((read $ printTree a) :: Double)
lowercase :: String -> String
lowercase "" = ""
lowercase (c:cs) = toLower c : cs
has_prefix :: Eq a => [a] -> [a] -> Bool
has_prefix pre s = take (length pre) s == pre
new_ext :: String -> FilePath -> FilePath
new_ext s fn = dropExtension fn ++ s
imports :: Module -> [String]
imports (Module _ _ xs) = [ userc a | ImportD a _ <- xs ]
user :: Print a => a -> String
user = lowercase . userc
userc :: Print a => a -> String
userc a = printTree a ++ "_"
my_system :: String -> IO ()
my_system s = do
putStrLn $ "system:" ++ s
ec <- system s
case ec of
ExitSuccess -> return ()
ExitFailure i -> error $ "exiting(" ++ show i ++ ")"