> module Epic.Language where
> import Control.Monad
> import System
> import System.IO
> import System.Directory
> import System.Environment
>
> data CompileOptions = KeepC
> | Trace
> | ShowBytecode
> | ShowParseTree
> | MakeHeader FilePath
> | GCCOpt String
> | Debug
> | Checking Int
> | ExternalMain
> | MainInc FilePath
> deriving Eq
Raw data types. Int, Char, Bool are unboxed.
> data Type = TyInt
> | TyChar
> | TyBool
> | TyFloat
> | TyBigInt
> | TyBigFloat
> | TyString
> | TyPtr
> | TyUnit
> | TyAny
> | TyData
> | TyCType String
> | TyFun
> deriving Eq
> instance Show Type where
> show TyInt = "Int"
> show TyChar = "Char"
> show TyBool = "Bool"
> show TyFloat = "Float"
> show TyBigInt = "BigInt"
> show TyBigFloat = "BigFloat"
> show TyString = "String"
> show TyPtr = "Ptr"
> show TyUnit = "Unit"
> show TyAny = "Any"
> show TyData = "Data"
> show (TyCType s) = "CType " ++ s
> show TyFun = "Fun"
> data Const = MkInt Int
> | MkBigInt Integer
> | MkChar Char
> | MkFloat Float
> | MkBigFloat Double
> | MkString String
> | MkBool Bool
> | MkUnit
> | MkUnused
> deriving (Show, Eq)
> data Name = UN String
> | MN String Int
> deriving Eq
> instance Show Name where
> show (UN str) = "_U_"++str
> show (MN str i) = "_M_"++show i++"_"++str
> showuser (UN str) = str
> showuser (MN str i) = "["++str++"_"++show i++"]"
> quotename [] = ""
> quotename ('_':cs) = "__"++quotename cs
> quotename ('\'':cs) = "_PR_"++quotename cs
> quotename ('?':cs) = "_QU_"++quotename cs
> quotename ('$':cs) = "_DO_"++quotename cs
> quotename ('#':cs) = "_HA_"++quotename cs
> quotename ('@':cs) = "_AT_"++quotename cs
> quotename (c:cs) = c:(quotename cs)
> showC n = quotename (show n)
> type Context = [(Name,([Type],Type))]
Get the arity of a definition in the context
> arity x ctxt = case lookup x ctxt of
> Nothing -> error $ "No such function " ++ show x
> (Just (args,ret)) -> length args
> type Tag = Int
> data Expr = V Int
> | R Name
> | App Expr [Expr]
> | Lazy Expr
> | Effect Expr
> | Con Tag [Expr]
> | Const Const
> | Proj Expr Int
> | Case Expr [CaseAlt]
> | If Expr Expr Expr
> | While Expr Expr
> | WhileAcc Expr Expr Expr
> | Op Op Expr Expr
> | Let Name Type Expr Expr
> | LetM Name Expr Expr
> | Update Int Expr Expr
> | Lam Name Type Expr
> | Error String
> | Impossible
> | WithMem Allocator Expr Expr
> | ForeignCall Type String [(Expr, Type)]
> | LazyForeignCall Type String [(Expr, Type)]
> deriving Eq
> data CaseAlt = Alt { alt_tag :: Tag,
> alt_args :: [(Name, Type)],
> alt_expr :: Expr
> }
> | ConstAlt { alt_const :: Int,
> alt_expr :: Expr }
> | DefaultCase { alt_expr :: Expr }
> deriving Eq
> instance Ord CaseAlt where
> compare (Alt t1 _ _) (Alt t2 _ _) = compare t1 t2
> compare (Alt _ _ _) (DefaultCase _) = LT
> compare (DefaultCase _) (Alt _ _ _) = GT
> compare _ _ = EQ
> data Allocator = FixedPool | GrowablePool
> deriving Eq
> data Op = Plus | Minus | Times | Divide | Modulo
> | OpEQ | OpLT | OpLE | OpGT | OpGE
> | FPlus | FMinus | FTimes | FDivide
> | OpFEQ | OpFLT | OpFLE | OpFGT | OpFGE
> | ShL | ShR
> deriving (Show, Eq)
> instance Show CaseAlt where
> show (DefaultCase e) = "default -> " ++ show e
> show (ConstAlt i e) = show i ++ " -> " ++ show e
> show (Alt t args e) = "Con " ++ show t ++ show args ++ " -> " ++ show e
> instance Show Expr where
> show (V i) = "var" ++ show i
> show (R n) = show n
> show (App f as) = show f ++ show as
> show (Lazy e) = "%lazy(" ++ show e ++ ")"
> show (Effect e) = "%effect(" ++ show e ++ ")"
> show (Con t es) = "Con " ++ show t ++ show es
> show (Const c) = show c
> show (Proj e i) = show e ++ "!" ++ show i
> show (Case e alts) = "case " ++ show e ++ " of " ++ show alts
> show (If x t e) = "if " ++ show x ++ " then " ++ show t ++ " else " ++ show e
> show (While e b) = "%while(" ++ show e ++ "," ++ show b ++ ")"
> show (WhileAcc e b a) = "%while(" ++ show e ++ ", " ++ show b ++
> ", " ++ show a ++ ")"
> show (Op o l r) = "(" ++ show l ++ " " ++ show o ++ " " ++ show r ++")"
> show (Let n t v e) = "let " ++ show n ++ ":" ++ show t ++ " = " ++
> show v ++ " in " ++ show e
> show (LetM n v e) = "let! " ++ show n ++ " = " ++
> show v ++ " in " ++ show e
> show (Update n v e) = "let! var" ++ show n ++ " = " ++
> show v ++ " in " ++ show e
> show (Lam n t e) = "\\ " ++ show n ++ ":" ++ show t ++ " . " ++
> show e
> show (Error e) = "error(" ++ show e ++ ")"
> show Impossible = "Impossible"
> show (WithMem a m e) = "%memory(" ++ show a ++ "," ++ show m ++ ", " ++ show e ++ ")"
> show (ForeignCall t s as) = "foreign " ++ show t ++ " " ++
> show s ++ show as
> show (LazyForeignCall t s as) = "lazy foreign " ++ show t ++ " " ++
> show s ++ show as
> instance Show Allocator where
> show FixedPool = "%fixed"
> show GrowablePool = "%growable"
Supercombinator definitions
> data Func = Bind { fun_args :: [(Name, Type)],
> locals :: Int,
> defn :: Expr,
> flags :: [CGFlag]}
> deriving Show
Programs
> data Decl = Decl { fname :: Name,
> frettype :: Type,
> fdef :: Func,
> fexport :: Maybe String,
> fcompflags :: [CGFlag]
> }
> | Extern { fname :: Name,
> frettype :: Type,
> fargs :: [Type] }
> | Include String
> | Link String
> | CType String
> deriving Show
> data CGFlag = Inline | Strict
> deriving (Show, Eq)
> data Result r = Success r
> | Failure String String Int
> deriving (Show, Eq)
>
> instance Monad Result where
> (Success r) >>= k = k r
> (Failure err fn line) >>= k = Failure err fn line
> return = Success
> fail s = Failure s "(no file)" 0
>
> instance MonadPlus Result where
> mzero = Failure "Error" "(no file)" 0
> mplus (Success x) _ = (Success x)
> mplus (Failure _ _ _) y = y
>
> appForm :: Expr -> Bool
appForm (App _ _) = True
appForm (V _) = True
> appForm (R _) = True
appForm (Con _ _) = True
appForm (Const _) = True
appForm (LazyForeignCall _ _ _) = True
> appForm _ = False
> checkLevel :: [CompileOptions] -> Int
> checkLevel [] = 1
> checkLevel (Checking i:_) = i
> checkLevel (_:xs) = checkLevel xs
Temp files for compiler output
> tempfile :: IO (FilePath, Handle)
> tempfile = do env <- environment "TMPDIR"
> let dir = case env of
> Nothing -> "/tmp"
> (Just d) -> d
> openTempFile dir "esc"
> environment :: String -> IO (Maybe String)
> environment x = catch (do e <- getEnv x
> return (Just e))
> (\_ -> return Nothing)
Some tests
foo x = let y = case x of
c1 a b -> a b
c2 c -> bar (c+2)
in y+3
testctxt = [((UN "foo"),([TyData], TyInt)),
((UN "bar"),([TyInt], TyInt))]
testprog = Bind [TyData] 3 $
Let (UN "y") TyInt (Case (V 0)
[Alt 0 [TyFun,TyInt] (App (V 1) [V 2]),
Alt 1 [TyInt] (App (R (UN "bar")) [Op Plus (V 1) (Const (MkInt 2))])])
(Op Plus (V 1) (Const (MkInt 3)))