module E.PrimDecode(processPrim) where
import Text.Printf
import C.Prims
import Cmm.Op(readTy,Ty)
import Data.Maybe
import DataConstructors
import E.E
import E.Values
import FrontEnd.SrcLoc
import FrontEnd.Tc.Kind
import FrontEnd.Warning
import Name.Name
import Name.Names
import PackedString
import StringTable.Atom
import Support.CanType
import Support.FreeVars
import Util.Gen
import qualified Cmm.Op as Op
import qualified Data.Map as Map
data Typ = [BType] :-> BType
deriving (Show)
data BType
= BKind KBase
| BTup [BType]
| BState
instance Show BType where
showsPrec n (BKind k) = showsPrec n k
showsPrec _ BState = showString "State#"
showsPrec n (BTup ts) = showsPrec n ts
star = [] :-> BKind Star
hash = [] :-> BKind KHash
starHash = [] :-> BKind KQuestQuest
state = [] :-> BState
utup ~([] :-> t1) ~([] :-> t2) = [] :-> BTup [t1,t2]
utup1 ~([] :-> t1) = [] :-> BTup [t1]
array = hash
bang = hash
infixr 3 +>
(+>) :: Typ -> Typ -> Typ
~([] :-> k) +> ks :-> rt = (k:ks) :-> rt
infix 1 ==>
a ==> b = (a,b)
plainPrimMap :: Map.Map Atom Typ
plainPrimMap = Map.fromList
[ "seq" ==> star +> starHash +> starHash
, "dependingOn" ==> star +> starHash +> star
, "newWorld__" ==> star +> state
, "unsafeCoerce" ==> star +> star
, "options_target" ==> hash
, "touch_" ==> starHash +> state +> state
, "zero" ==> starHash
, "one" ==> starHash
, "box" ==> hash +> star
, "unbox" ==> star +> hash
, "exitFailure__" ==> hash +> hash
, "constPeekByte" ==> hash +> hash
, "newArray__" ==> hash +> star +> state +> utup state array
, "newBlankArray__"==> hash +> state +> utup state array
, "copyArray__" ==> hash +> hash +> hash +> array +> array +> state +> state
, "readArray__" ==> array +> hash +> state +> utup state star
, "writeArray__" ==> array +> hash +> star +> state +> state
, "indexArray__" ==> array +> hash +> utup1 star
, "toBang_" ==> star +> bang
, "fromBang_" ==> bang +> star
, "isWHNF" ==> star +> hash
, "isInHeap" ==> bang +> hash
, "bangPtr" ==> bang +> hash
, "bangBits" ==> bang +> hash
] `Map.union` fmap (const (starHash +> starHash)) incDec
`Map.union` fmap (const star) primBoundMap
primBoundMap = Map.fromList [("maxBound",PrimMaxBound),
("minBound",PrimMinBound),
("umaxBound",PrimUMaxBound)]
incDec = Map.fromList [("increment",Op.Add),("decrement",Op.Sub),
("fincrement",Op.FAdd),("fdecrement",Op.FSub)]
ashow op = toAtom (show op)
binOpMap = Map.fromList [ ashow op ==> (op, starHash +> starHash +> starHash)
| op :: Op.BinOp <- [minBound .. maxBound] ]
unOpMap = Map.fromList [ ashow op ==> (op,starHash +> starHash)
| op :: Op.UnOp <- [minBound .. maxBound] ]
convOpMap = Map.fromList [ ashow op ==> (op,starHash +> starHash)
| op :: Op.ConvOp <- [minBound .. maxBound] ]
pairWith :: (a -> b -> c)
-> [a] -> [b] -> Maybe [c]
pairWith f xs ys = g xs ys [] where
g [] [] rs = Just $ reverse rs
g (x:xs) (y:ys) rs = g xs ys (f x y:rs)
g _ _ _ = Nothing
ePrim prim as t = EPrim prim as t
processPrim :: MonadWarn m
=> DataTable
-> SrcLoc
-> Atom
-> [E]
-> E
-> Requires
-> m E
processPrim dataTable srcLoc pName args rType req = ans where
passThrough = EPrim (PrimPrim pName) args rType
ans = checkOp binOpMap doBinOp $ checkOp unOpMap (doUnOp Op.UnOp) $
checkOp convOpMap (doUnOp Op.ConvOp) primCheckOther
checkOp table yesMatch noMatch = case Map.lookup pName table of
Just (op,ty) -> checkType ty (return passThrough) (yesMatch op)
Nothing -> noMatch
primCheckOther = case Map.lookup pName plainPrimMap of
Just ty -> checkType ty (return passThrough) (primOther pName args)
Nothing -> primPrefix (show pName) args
where primOther "box" [a] = return ans where
Just (ExtTypeBoxed cna _ _) = lookupExtTypeInfo dataTable rType
ans = ELit litCons { litName = cna, litArgs = [a], litType = rType }
primOther "unbox" [a] = return ans where
(vara:_) = newIds (freeVars (a,rType))
ans = unbox dataTable a vara $ \tvra -> EVar tvra
primOther "seq" [a,b] = return $ prim_seq a b
primOther "exitFailure__" [_] = return $ EError "" rType
primOther "options_target" _ = return (ELit (LitInt 0 rType))
primOther "constPeekByte" [a] = return $ ePrim (Peek Op.bits8) [a] rType
primOther op [a] | Just x <- Map.lookup op incDec = do
(pa,(ta,sta)) <- extractPrimitive dataTable a
Just ret <- return $ boxResult dataTable rType $ \tr str ->
ePrim (Op (Op.BinOp x (stringToOpTy ta) (stringToOpTy ta)) tr)
[pa, ELit (LitInt 1 sta)] str
return ret
primOther op [] | Just x <- Map.lookup op primBoundMap = do
Just res <- return $ boxResult dataTable rType $ \tr str ->
ePrim (PrimTypeInfo tr tr x) [] str
return res
primOther op [] | Just x <- lookup op ["zero" ==> 0,"one" ==> 1] = do
Just res <- return $ boxResult dataTable rType $ \tr str ->
ELit (LitInt x str)
return res
primOther _ _ = return passThrough
preType n s = getPrefix n s >>= Op.readTy
checkType' ty os = checkType ty (return passThrough) os
primPrefix (preType "peek." -> Just c) ~[a,w] = checkType'
(hash +> state +> utup state hash) $ return
(ePrim (Peek c) [w,a] rType)
primPrefix (preType "poke." -> Just c) ~[a,v,w] = checkType'
(hash +> hash +> state +> state) $ return
(ePrim (Poke c) [w,a,v] rType)
primPrefix (preType "sizeOf." -> Just c) _ = primInfo c Op.bits32 PrimSizeOf
primPrefix (preType "alignmentOf." -> Just c) _ = primInfo c Op.bits32 PrimAlignmentOf
primPrefix (preType "maxBound." -> Just c) _ = primInfo c c PrimMaxBound
primPrefix (preType "minBound." -> Just c) _ = primInfo c c PrimMinBound
primPrefix (preType "umaxBound." -> Just c) _ = primInfo c c PrimUMaxBound
primPrefix (getPrefix "options_" -> Just c) _ =
return (ePrim (CConst req (packString $ "JHC_" ++ c)) [] rType)
primPrefix (getPrefix "const." -> Just c) _ = checkType' star $ do
Just ret <- return $ boxResult dataTable rType $ \tr str ->
ePrim (CConst req $ packString c) [] str
return ret
primPrefix (getPrefix "error." -> Just c) _ = return (EError c rType)
primPrefix _ _ = primUnknown
primInfo c cr wh = checkType' (hash +> hash) $ return
(ePrim (PrimTypeInfo c cr wh) [] rType)
primUnknown = do
warn srcLoc (PrimitiveUnknown pName) $
printf "Unknown primitive '%s'" (fromAtom pName :: String)
return passThrough
doBinOp op = do
let [a,b] = args
(pa,(ta,_)) <- extractPrimitive dataTable a
(pb,(tb,_)) <- extractPrimitive dataTable b
Just res <- return $ boxResult dataTable rType $ \tr str ->
ePrim Op { primCOp = Op.BinOp op (stot op 1 ta) (stot op 2 tb), primRetTy = tr } [pa, pb] str
return res
doUnOp bOp op = do
let [a] = args
(pa,(ta,_)) <- extractPrimitive dataTable a
Just res <- return $ boxResult dataTable rType $ \tr str ->
ePrim Op { primCOp = bOp op (stot op 1 ta), primRetTy = tr } [pa] str
return res
checkType (tas :-> trt) onFail onPass =
case pairWith match tas (map getType args) of
Just cs | and cs, match trt rType -> onPass
_ -> do
warn srcLoc PrimitiveBadType $
printf "Primitive type mismatch. expected '%s' but found '%s -> %s'"
(show (tas :-> trt)) (show $ map (getType . getType) args) (show $ getType rType)
onFail
match k e = g k where
t = getType e
g BState = isState_ e
g (BTup ks) = case e of
ELit (LitCons { litName = n, litArgs = as }) ->
n == unboxedNameTuple TypeConstructor (length as) && matches ks as
_ -> False
g (BKind k) = f k
f Star = t == eStar
f KHash = t == eHash
f KQuestQuest = t == eStar || t == eHash
f _ = False
matches ks es = maybe False and $ pairWith match ks es
type T = E
boxResult :: DataTable -> T -> (Ty -> T -> E) -> Maybe E
boxResult dataTable t fn = mdo
(res,(ta,sta)) <- boxPrimitive dataTable (fn (stringToOpTy ta) sta) t
return res
stringToOpTy :: ExtType -> Ty
stringToOpTy s = stringToOpTy' "" s
stringToOpTy' :: String -> ExtType -> Ty
stringToOpTy' x (show -> s) = case readTy s of
Just t -> t
_ -> error $ printf "stringToOpTy(%s): '%s'" x s
stot :: Show a => a -> Int -> ExtType -> Ty
stot op n s = stringToOpTy' (show op ++ show n) s
unbox :: DataTable -> E -> Id -> (TVr -> E) -> E
unbox dataTable e vn wtd = eCase e [Alt (litCons { litName = cna, litArgs = [tvra], litType = te }) (wtd tvra)] Unknown where
te = getType e
tvra = tVr vn sta
(ExtTypeBoxed cna sta _) = fromMaybe (error $ "lookupExtTypeInfo(unbox): " ++ show te) $ lookupExtTypeInfo dataTable te