module Agda.Compiler.MAlonzo.Primitives where
import Control.Monad.State
import Data.Char
import Data.List as L
import Data.Map as M
import qualified Language.Haskell.Exts.Syntax as HS
import Agda.Compiler.Common
import Agda.Compiler.ToTreeless
import Agda.Compiler.MAlonzo.Compiler (closedTerm)
import Agda.Compiler.MAlonzo.Misc
import Agda.Compiler.MAlonzo.Pretty
import Agda.Syntax.Common
import Agda.Syntax.Internal
import Agda.TypeChecking.Monad
import Agda.TypeChecking.Monad.Builtin
import Agda.TypeChecking.Primitive
import Agda.TypeChecking.Reduce
import Agda.TypeChecking.Pretty
import Agda.Utils.Monad
import Agda.Utils.Except
import qualified Agda.Utils.HashMap as HMap
#include "undefined.h"
import Agda.Utils.Impossible
checkTypeOfMain :: QName -> Type -> TCM [HS.Decl] -> TCM [HS.Decl]
checkTypeOfMain q ty ret
| show (nameConcrete $ qnameName q) /= "main" = ret
| otherwise = do
Def io _ <- ignoreSharing <$> primIO
ty <- normalise ty
case ignoreSharing $ unEl ty of
Def d _ | d == io -> (mainAlias :) <$> ret
_ -> do
err <- fsep $
pwords "The type of main should be" ++
[prettyTCM io] ++ pwords " A, for some A. The given type is" ++ [prettyTCM ty]
typeError $ GenericError $ show err
where
mainAlias = HS.FunBind [HS.Match dummy mainLHS [] Nothing mainRHS emptyBinds ]
mainLHS = HS.Ident "main"
mainRHS = HS.UnGuardedRhs $ HS.Var $ HS.UnQual $ unqhname "d" q
importsForPrim :: TCM [HS.ModuleName]
importsForPrim =
fmap (++ [HS.ModuleName "Data.Text"]) $
xForPrim $
L.map (\(s, ms) -> (s, return (L.map HS.ModuleName ms))) $
[ "CHAR" |-> ["Data.Char"]
, "primIsDigit" |-> ["Data.Char"]
, "primIsLower" |-> ["Data.Char"]
, "primIsDigit" |-> ["Data.Char"]
, "primIsAlpha" |-> ["Data.Char"]
, "primIsSpace" |-> ["Data.Char"]
, "primIsAscii" |-> ["Data.Char"]
, "primIsLatin1" |-> ["Data.Char"]
, "primIsPrint" |-> ["Data.Char"]
, "primIsHexDigit" |-> ["Data.Char"]
, "primToUpper" |-> ["Data.Char"]
, "primToLower" |-> ["Data.Char"]
]
where (|->) = (,)
xForPrim :: [(String, TCM [a])] -> TCM [a]
xForPrim table = do
qs <- HMap.keys <$> curDefs
bs <- toList <$> gets stBuiltinThings
let getName (Builtin (Def q _)) = q
getName (Builtin (Con q _)) = conName q
getName (Builtin (Shared p)) = getName (Builtin $ derefPtr p)
getName (Builtin _) = __IMPOSSIBLE__
getName (Prim (PrimFun q _ _)) = q
concat <$> sequence [ maybe (return []) id $ L.lookup s table
| (s, def) <- bs, getName def `elem` qs ]
primBody :: String -> TCM HS.Exp
primBody s = maybe unimplemented (either (hsVarUQ . HS.Ident) id <$>) $
L.lookup s $
[
"primIntegerPlus" |-> binAsis "(+)" "Integer"
, "primIntegerMinus" |-> binAsis "(-)" "Integer"
, "primIntegerTimes" |-> binAsis "(*)" "Integer"
, "primIntegerDiv" |-> binAsis "div" "Integer"
, "primIntegerMod" |-> binAsis "mod" "Integer"
, "primIntegerEquality"|-> rel "(==)" "Integer"
, "primIntegerLess" |-> rel "(<)" "Integer"
, "primIntegerAbs" |-> return "(abs :: Integer -> Integer)"
, "primNatToInteger" |-> return "(id :: Integer -> Integer)"
, "primShowInteger" |-> return "(Data.Text.pack . show :: Integer -> Data.Text.Text)"
, "primLevelZero" |-> return "()"
, "primLevelSuc" |-> return "(\\ _ -> ())"
, "primLevelMax" |-> return "(\\ _ _ -> ())"
, "primNatPlus" |-> binNat "(+)"
, "primNatMinus" |-> binNat "(\\ x y -> max 0 (x - y))"
, "primNatTimes" |-> binNat "(*)"
, "primNatDivSucAux" |-> binNat4 "(\\ k m n j -> k + div (max 0 $ n + m - j) (m + 1))"
, "primNatModSucAux" |-> binNat4 "(\\ k m n j -> if n > j then mod (n - j - 1) (m + 1) else (k + n))"
, "primNatEquality" |-> relNat "(==)"
, "primNatLess" |-> relNat "(<)"
, "primNatToFloat" |-> return "(fromIntegral :: Integer -> Double)"
, "primFloatPlus" |-> return "((+) :: Double -> Double -> Double)"
, "primFloatMinus" |-> return "((-) :: Double -> Double -> Double)"
, "primFloatTimes" |-> return "((*) :: Double -> Double -> Double)"
, "primFloatDiv" |-> return "((/) :: Double -> Double -> Double)"
, "primFloatEquality" |-> return "((\\ x y -> if isNaN x && isNaN y then True else x == y) :: Double -> Double -> Bool)"
, "primFloatLess" |-> return (unwords
[ "((\\ x y ->"
, "let isNegInf z = z < 0 && isInfinite z in"
, "if isNegInf y then False else"
, "if isNegInf x then True else"
, "if isNaN x then True else"
, "x < y) :: Double -> Double -> Bool)" ])
, "primFloatSqrt" |-> return "(sqrt :: Double -> Double)"
, "primRound" |-> return "(round :: Double -> Integer)"
, "primFloor" |-> return "(floor :: Double -> Integer)"
, "primCeiling" |-> return "(ceiling :: Double -> Integer)"
, "primExp" |-> return "(exp :: Double -> Double)"
, "primLog" |-> return "(log :: Double -> Double)"
, "primSin" |-> return "(sin :: Double -> Double)"
, "primShowFloat" |-> return "(Data.Text.pack . (\\ x -> if isNegativeZero x then \"0.0\" else show x) :: Double -> Data.Text.Text)"
, "primCharEquality" |-> rel "(==)" "Char"
, "primIsLower" |-> return "Data.Char.isLower"
, "primIsDigit" |-> return "Data.Char.isDigit"
, "primIsAlpha" |-> return "Data.Char.isAlpha"
, "primIsSpace" |-> return "Data.Char.isSpace"
, "primIsAscii" |-> return "Data.Char.isAscii"
, "primIsLatin1" |-> return "Data.Char.isLatin1"
, "primIsPrint" |-> return "Data.Char.isPrint"
, "primIsHexDigit" |-> return "Data.Char.isHexDigit"
, "primToUpper" |-> return "Data.Char.toUpper"
, "primToLower" |-> return "Data.Char.toLower"
, "primCharToNat" |-> return "(fromIntegral . fromEnum :: Char -> Integer)"
, "primNatToChar" |-> return "(toEnum . fromIntegral :: Integer -> Char)"
, "primShowChar" |-> return "(Data.Text.pack . show :: Char -> Data.Text.Text)"
, "primStringToList" |-> return "Data.Text.unpack"
, "primStringFromList" |-> return "Data.Text.pack"
, "primStringAppend" |-> binAsis "Data.Text.append" "Data.Text.Text"
, "primStringEquality" |-> rel "(==)" "Data.Text.Text"
, "primShowString" |-> return "Data.Text.unpack"
, "primQNameEquality" |-> rel "(==)" "MAlonzo.RTE.QName"
, "primQNameLess" |-> rel "(<)" "MAlonzo.RTE.QName"
, "primShowQName" |-> return "Data.Text.pack . MAlonzo.RTE.qnameString"
, "primMetaEquality" |-> rel "(==)" "Integer"
, "primMetaLess" |-> rel "(<)" "Integer"
, "primShowMeta" |-> return "\\ x -> Data.Text.pack (\"_\" ++ show (x :: Integer))"
, "primForce" |-> return "\\ _ _ _ _ x f -> f $! x"
, "primForceLemma" |-> return "erased"
, ("primTrustMe" , Right <$> do
refl <- primRefl
closedTerm =<< (closedTermToTreeless $ lam "a" (lam "A" (lam "x" (lam "y" refl)))))
]
where
x |-> s = (x, Left <$> s)
bin blt op ty from to = do
from' <- bltQual' blt from
to' <- bltQual' blt to
return $ repl [op, opty ty, from', to'] $
"\\ x y -> <<3>> ((<<0>> :: <<1>>) (<<2>> x) (<<2>> y))"
binNat op = return $ repl [op] "(<<0>> :: Integer -> Integer -> Integer)"
binNat4 op = return $ repl [op] "(<<0>> :: Integer -> Integer -> Integer -> Integer -> Integer)"
binAsis op ty = return $ repl [op, opty ty] $ "((<<0>>) :: <<1>>)"
rel' toTy op ty = do
return $ repl [op, ty, toTy] $
"(\\ x y -> (<<0>> :: <<1>> -> <<1>> -> Bool) (<<2>> x) (<<2>> y))"
relNat op = do
return $ repl [op] $
"(<<0>> :: Integer -> Integer -> Bool)"
rel op ty = rel' "" op ty
opty t = t ++ "->" ++ t ++ "->" ++ t
unimplemented = typeError $ NotImplemented s
lam x t = Lam (setHiding Hidden defaultArgInfo) (Abs x t)
noCheckCover :: QName -> TCM Bool
noCheckCover q = (||) <$> isBuiltin q builtinNat <*> isBuiltin q builtinInteger
pconName :: String -> TCM String
pconName s = toS . ignoreSharing =<< getBuiltin s where
toS (Con q _) = prettyPrint <$> conhqn (conName q)
toS (Lam _ t) = toS (unAbs t)
toS _ = mazerror $ "pconName" ++ s
bltQual' :: String -> String -> TCM String
bltQual' b s = prettyPrint <$> bltQual b s