module Agda.Compiler.Treeless.Builtin (translateBuiltins) where
import qualified Agda.Syntax.Internal as I
import Agda.Syntax.Position
import Agda.Syntax.Treeless
import Agda.Syntax.Literal
import Agda.TypeChecking.Substitute
import Agda.TypeChecking.Monad
import Agda.Compiler.Treeless.Subst ()
import Agda.Utils.Impossible
data BuiltinKit = BuiltinKit
{ BuiltinKit -> QName -> Bool
isZero :: QName -> Bool
, BuiltinKit -> QName -> Bool
isSuc :: QName -> Bool
, BuiltinKit -> QName -> Bool
isPos :: QName -> Bool
, BuiltinKit -> QName -> Bool
isNegSuc :: QName -> Bool
, BuiltinKit -> QName -> Bool
isPlus :: QName -> Bool
, BuiltinKit -> QName -> Bool
isTimes :: QName -> Bool
, BuiltinKit -> QName -> Bool
isLess :: QName -> Bool
, BuiltinKit -> QName -> Bool
isEqual :: QName -> Bool
, BuiltinKit -> QName -> Bool
isForce :: QName -> Bool
, BuiltinKit -> QName -> Bool
isWord64FromNat :: QName -> Bool
, BuiltinKit -> QName -> Bool
isWord64ToNat :: QName -> Bool
}
builtinKit :: TCM BuiltinKit
builtinKit :: TCM BuiltinKit
builtinKit =
(QName -> Bool)
-> (QName -> Bool)
-> (QName -> Bool)
-> (QName -> Bool)
-> (QName -> Bool)
-> (QName -> Bool)
-> (QName -> Bool)
-> (QName -> Bool)
-> (QName -> Bool)
-> (QName -> Bool)
-> (QName -> Bool)
-> BuiltinKit
BuiltinKit forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall {f :: * -> *} {b}.
(Eq b, HasBuiltins f) =>
(Term -> Maybe b) -> String -> f (b -> Bool)
isB Term -> Maybe QName
con String
builtinZero
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> forall {f :: * -> *} {b}.
(Eq b, HasBuiltins f) =>
(Term -> Maybe b) -> String -> f (b -> Bool)
isB Term -> Maybe QName
con String
builtinSuc
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> forall {f :: * -> *} {b}.
(Eq b, HasBuiltins f) =>
(Term -> Maybe b) -> String -> f (b -> Bool)
isB Term -> Maybe QName
con String
builtinIntegerPos
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> forall {f :: * -> *} {b}.
(Eq b, HasBuiltins f) =>
(Term -> Maybe b) -> String -> f (b -> Bool)
isB Term -> Maybe QName
con String
builtinIntegerNegSuc
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> forall {f :: * -> *} {b}.
(Eq b, HasBuiltins f) =>
(Term -> Maybe b) -> String -> f (b -> Bool)
isB Term -> Maybe QName
def String
builtinNatPlus
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> forall {f :: * -> *} {b}.
(Eq b, HasBuiltins f) =>
(Term -> Maybe b) -> String -> f (b -> Bool)
isB Term -> Maybe QName
def String
builtinNatTimes
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> forall {f :: * -> *} {b}.
(Eq b, HasBuiltins f) =>
(Term -> Maybe b) -> String -> f (b -> Bool)
isB Term -> Maybe QName
def String
builtinNatLess
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> forall {f :: * -> *} {b}.
(Eq b, HasBuiltins f) =>
(Term -> Maybe b) -> String -> f (b -> Bool)
isB Term -> Maybe QName
def String
builtinNatEquals
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> forall {f :: * -> *} {b}.
(Eq b, HasBuiltins f) =>
(PrimFun -> Maybe b) -> String -> f (b -> Bool)
isP PrimFun -> Maybe QName
pf String
"primForce"
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> forall {f :: * -> *} {b}.
(Eq b, HasBuiltins f) =>
(PrimFun -> Maybe b) -> String -> f (b -> Bool)
isP PrimFun -> Maybe QName
pf String
"primWord64FromNat"
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> forall {f :: * -> *} {b}.
(Eq b, HasBuiltins f) =>
(PrimFun -> Maybe b) -> String -> f (b -> Bool)
isP PrimFun -> Maybe QName
pf String
"primWord64ToNat"
where
con :: Term -> Maybe QName
con (I.Con ConHead
c ConInfo
_ Elims
_) = forall (f :: * -> *) a. Applicative f => a -> f a
pure forall a b. (a -> b) -> a -> b
$ ConHead -> QName
I.conName ConHead
c
con Term
_ = forall a. Maybe a
Nothing
def :: Term -> Maybe QName
def (I.Def QName
d Elims
_) = forall (f :: * -> *) a. Applicative f => a -> f a
pure QName
d
def Term
_ = forall a. Maybe a
Nothing
pf :: PrimFun -> Maybe QName
pf = forall a. a -> Maybe a
Just forall b c a. (b -> c) -> (a -> b) -> a -> c
. PrimFun -> QName
primFunName
is :: (a -> Maybe b) -> f (Maybe a) -> f (b -> Bool)
is a -> Maybe b
a f (Maybe a)
b = forall b a. b -> (a -> b) -> Maybe a -> b
maybe (forall a b. a -> b -> a
const Bool
False) forall a. Eq a => a -> a -> Bool
(==) forall b c a. (b -> c) -> (a -> b) -> a -> c
. (a -> Maybe b
a forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<<) forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> f (Maybe a)
b
isB :: (Term -> Maybe b) -> String -> f (b -> Bool)
isB Term -> Maybe b
a String
b = forall {f :: * -> *} {b} {a}.
(Functor f, Eq b) =>
(a -> Maybe b) -> f (Maybe a) -> f (b -> Bool)
is Term -> Maybe b
a (forall (m :: * -> *). HasBuiltins m => String -> m (Maybe Term)
getBuiltin' String
b)
isP :: (PrimFun -> Maybe b) -> String -> f (b -> Bool)
isP PrimFun -> Maybe b
a String
p = forall {f :: * -> *} {b} {a}.
(Functor f, Eq b) =>
(a -> Maybe b) -> f (Maybe a) -> f (b -> Bool)
is PrimFun -> Maybe b
a (forall (m :: * -> *). HasBuiltins m => String -> m (Maybe PrimFun)
getPrimitive' String
p)
translateBuiltins :: TTerm -> TCM TTerm
translateBuiltins :: TTerm -> TCM TTerm
translateBuiltins TTerm
t = do
BuiltinKit
kit <- TCM BuiltinKit
builtinKit
forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ BuiltinKit -> TTerm -> TTerm
transform BuiltinKit
kit TTerm
t
transform :: BuiltinKit -> TTerm -> TTerm
transform :: BuiltinKit -> TTerm -> TTerm
transform BuiltinKit{QName -> Bool
isWord64ToNat :: QName -> Bool
isWord64FromNat :: QName -> Bool
isForce :: QName -> Bool
isEqual :: QName -> Bool
isLess :: QName -> Bool
isTimes :: QName -> Bool
isPlus :: QName -> Bool
isNegSuc :: QName -> Bool
isPos :: QName -> Bool
isSuc :: QName -> Bool
isZero :: QName -> Bool
isWord64ToNat :: BuiltinKit -> QName -> Bool
isWord64FromNat :: BuiltinKit -> QName -> Bool
isForce :: BuiltinKit -> QName -> Bool
isEqual :: BuiltinKit -> QName -> Bool
isLess :: BuiltinKit -> QName -> Bool
isTimes :: BuiltinKit -> QName -> Bool
isPlus :: BuiltinKit -> QName -> Bool
isNegSuc :: BuiltinKit -> QName -> Bool
isPos :: BuiltinKit -> QName -> Bool
isSuc :: BuiltinKit -> QName -> Bool
isZero :: BuiltinKit -> QName -> Bool
..} = TTerm -> TTerm
tr
where
tr :: TTerm -> TTerm
tr = \case
TCon QName
c | QName -> Bool
isZero QName
c -> Integer -> TTerm
tInt Integer
0
| QName -> Bool
isSuc QName
c -> TTerm -> TTerm
TLam (Integer -> TTerm -> TTerm
tPlusK Integer
1 (Int -> TTerm
TVar Int
0))
| QName -> Bool
isPos QName
c -> TTerm -> TTerm
TLam (Int -> TTerm
TVar Int
0)
| QName -> Bool
isNegSuc QName
c -> TTerm -> TTerm
TLam forall a b. (a -> b) -> a -> b
$ Integer -> TTerm -> TTerm
tNegPlusK Integer
1 (Int -> TTerm
TVar Int
0)
TDef QName
f | QName -> Bool
isPlus QName
f -> TPrim -> TTerm
TPrim TPrim
PAdd
| QName -> Bool
isTimes QName
f -> TPrim -> TTerm
TPrim TPrim
PMul
| QName -> Bool
isLess QName
f -> TPrim -> TTerm
TPrim TPrim
PLt
| QName -> Bool
isEqual QName
f -> TPrim -> TTerm
TPrim TPrim
PEqI
| QName -> Bool
isWord64ToNat QName
f -> TPrim -> TTerm
TPrim TPrim
P64ToI
| QName -> Bool
isWord64FromNat QName
f -> TPrim -> TTerm
TPrim TPrim
PITo64
TApp (TDef QName
q) (TTerm
_ : TTerm
_ : TTerm
_ : TTerm
_ : TTerm
e : TTerm
f : [TTerm]
es)
| QName -> Bool
isForce QName
q -> TTerm -> TTerm
tr forall a b. (a -> b) -> a -> b
$ TTerm -> TTerm -> TTerm
TLet TTerm
e forall a b. (a -> b) -> a -> b
$ TTerm -> [TTerm] -> TTerm
mkTApp (TPrim -> TTerm -> TTerm -> TTerm
tOp TPrim
PSeq (Int -> TTerm
TVar Int
0) forall a b. (a -> b) -> a -> b
$ TTerm -> [TTerm] -> TTerm
mkTApp (forall a. Subst a => Int -> a -> a
raise Int
1 TTerm
f) [Int -> TTerm
TVar Int
0]) [TTerm]
es
TApp (TCon QName
s) [TTerm
e] | QName -> Bool
isSuc QName
s ->
case TTerm -> TTerm
tr TTerm
e of
TLit (LitNat Integer
n) -> Integer -> TTerm
tInt (Integer
n forall a. Num a => a -> a -> a
+ Integer
1)
TTerm
e | Just (Integer
i, TTerm
e) <- TTerm -> Maybe (Integer, TTerm)
plusKView TTerm
e -> Integer -> TTerm -> TTerm
tPlusK (Integer
i forall a. Num a => a -> a -> a
+ Integer
1) TTerm
e
TTerm
e -> Integer -> TTerm -> TTerm
tPlusK Integer
1 TTerm
e
TApp (TCon QName
c) [TTerm
e]
| QName -> Bool
isPos QName
c -> TTerm -> TTerm
tr TTerm
e
| QName -> Bool
isNegSuc QName
c ->
case TTerm -> TTerm
tr TTerm
e of
TLit (LitNat Integer
n) -> Integer -> TTerm
tInt (-Integer
n forall a. Num a => a -> a -> a
- Integer
1)
TTerm
e | Just (Integer
i, TTerm
e) <- TTerm -> Maybe (Integer, TTerm)
plusKView TTerm
e -> Integer -> TTerm -> TTerm
tNegPlusK (Integer
i forall a. Num a => a -> a -> a
+ Integer
1) TTerm
e
TTerm
e -> Integer -> TTerm -> TTerm
tNegPlusK Integer
1 TTerm
e
TCase Int
e CaseInfo
t TTerm
d [TAlt]
bs -> Int -> CaseInfo -> TTerm -> [TAlt] -> TTerm
TCase Int
e (CaseInfo -> [TAlt] -> CaseInfo
inferCaseType CaseInfo
t [TAlt]
bs) (TTerm -> TTerm
tr TTerm
d) forall a b. (a -> b) -> a -> b
$ forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap TAlt -> [TAlt]
trAlt [TAlt]
bs
where
trAlt :: TAlt -> [TAlt]
trAlt = \case
TACon QName
c Int
0 TTerm
b | QName -> Bool
isZero QName
c -> [Literal -> TTerm -> TAlt
TALit (Integer -> Literal
LitNat Integer
0) (TTerm -> TTerm
tr TTerm
b)]
TACon QName
c Int
1 TTerm
b | QName -> Bool
isSuc QName
c ->
case TTerm -> TTerm
tr TTerm
b of
TCase Int
0 CaseInfo
_ TTerm
d [TAlt]
bs' -> forall a b. (a -> b) -> [a] -> [b]
map TAlt -> TAlt
sucBranch [TAlt]
bs' forall a. [a] -> [a] -> [a]
++ [Integer -> TTerm -> TAlt
nPlusKAlt Integer
1 TTerm
d]
TTerm
b -> [Integer -> TTerm -> TAlt
nPlusKAlt Integer
1 TTerm
b]
where
sucBranch :: TAlt -> TAlt
sucBranch (TALit (LitNat Integer
i) TTerm
b) = Literal -> TTerm -> TAlt
TALit (Integer -> Literal
LitNat (Integer
i forall a. Num a => a -> a -> a
+ Integer
1)) forall a b. (a -> b) -> a -> b
$ TTerm -> TTerm -> TTerm
TLet (Integer -> TTerm
tInt Integer
i) TTerm
b
sucBranch TAlt
alt | Just (Integer
k, TTerm
b) <- TAlt -> Maybe (Integer, TTerm)
nPlusKView TAlt
alt =
Integer -> TTerm -> TAlt
nPlusKAlt (Integer
k forall a. Num a => a -> a -> a
+ Integer
1) forall a b. (a -> b) -> a -> b
$ TTerm -> TTerm -> TTerm
TLet (TPrim -> TTerm -> TTerm -> TTerm
tOp TPrim
PAdd (Int -> TTerm
TVar Int
0) (Integer -> TTerm
tInt Integer
1)) forall a b. (a -> b) -> a -> b
$
forall a. Subst a => Substitution' (SubstArg a) -> a -> a
applySubst ([Int -> TTerm
TVar Int
1, Int -> TTerm
TVar Int
0] forall a. DeBruijn a => [a] -> Substitution' a -> Substitution' a
++# forall a. Int -> Substitution' a -> Substitution' a
wkS Int
2 forall a. Substitution' a
idS) TTerm
b
sucBranch TAlt
_ = forall a. HasCallStack => a
__IMPOSSIBLE__
nPlusKAlt :: Integer -> TTerm -> TAlt
nPlusKAlt Integer
k TTerm
b = TTerm -> TTerm -> TAlt
TAGuard (TPrim -> TTerm -> TTerm -> TTerm
tOp TPrim
PGeq (Int -> TTerm
TVar Int
e) (Integer -> TTerm
tInt Integer
k)) forall a b. (a -> b) -> a -> b
$
TTerm -> TTerm -> TTerm
TLet (TPrim -> TTerm -> TTerm -> TTerm
tOp TPrim
PSub (Int -> TTerm
TVar Int
e) (Integer -> TTerm
tInt Integer
k)) TTerm
b
TACon QName
c Int
1 TTerm
b | QName -> Bool
isPos QName
c ->
case TTerm -> TTerm
tr TTerm
b of
TCase Int
0 CaseInfo
_ TTerm
d [TAlt]
bs -> forall a b. (a -> b) -> [a] -> [b]
map forall a. SubstWith TTerm a => a -> a
sub [TAlt]
bs forall a. [a] -> [a] -> [a]
++ [TTerm -> TAlt
posAlt TTerm
d]
TTerm
b -> [TTerm -> TAlt
posAlt TTerm
b]
where
sub :: SubstWith TTerm a => a -> a
sub :: forall a. SubstWith TTerm a => a -> a
sub = forall a. Subst a => Substitution' (SubstArg a) -> a -> a
applySubst (Int -> TTerm
TVar Int
e forall a. a -> Substitution' a -> Substitution' a
:# forall a. Substitution' a
IdS)
posAlt :: TTerm -> TAlt
posAlt TTerm
b = TTerm -> TTerm -> TAlt
TAGuard (TPrim -> TTerm -> TTerm -> TTerm
tOp TPrim
PGeq (Int -> TTerm
TVar Int
e) (Integer -> TTerm
tInt Integer
0)) forall a b. (a -> b) -> a -> b
$ forall a. SubstWith TTerm a => a -> a
sub TTerm
b
TACon QName
c Int
1 TTerm
b | QName -> Bool
isNegSuc QName
c ->
case TTerm -> TTerm
tr TTerm
b of
TCase Int
0 CaseInfo
_ TTerm
d [TAlt]
bs -> forall a b. (a -> b) -> [a] -> [b]
map TAlt -> TAlt
negsucBranch [TAlt]
bs forall a. [a] -> [a] -> [a]
++ [TTerm -> TAlt
negAlt TTerm
d]
TTerm
b -> [TTerm -> TAlt
negAlt TTerm
b]
where
body :: TTerm -> TTerm
body TTerm
b = TTerm -> TTerm -> TTerm
TLet (Integer -> TTerm -> TTerm
tNegPlusK Integer
1 (Int -> TTerm
TVar Int
e)) TTerm
b
negAlt :: TTerm -> TAlt
negAlt TTerm
b = TTerm -> TTerm -> TAlt
TAGuard (TPrim -> TTerm -> TTerm -> TTerm
tOp TPrim
PLt (Int -> TTerm
TVar Int
e) (Integer -> TTerm
tInt Integer
0)) forall a b. (a -> b) -> a -> b
$ TTerm -> TTerm
body TTerm
b
negsucBranch :: TAlt -> TAlt
negsucBranch (TALit (LitNat Integer
i) TTerm
b) = Literal -> TTerm -> TAlt
TALit (Integer -> Literal
LitNat (-Integer
i forall a. Num a => a -> a -> a
- Integer
1)) forall a b. (a -> b) -> a -> b
$ TTerm -> TTerm
body TTerm
b
negsucBranch TAlt
alt | Just (Integer
k, TTerm
b) <- TAlt -> Maybe (Integer, TTerm)
nPlusKView TAlt
alt =
TTerm -> TTerm -> TAlt
TAGuard (TPrim -> TTerm -> TTerm -> TTerm
tOp TPrim
PLt (Int -> TTerm
TVar Int
e) (Integer -> TTerm
tInt (-Integer
k))) forall a b. (a -> b) -> a -> b
$
TTerm -> TTerm
body forall a b. (a -> b) -> a -> b
$ TTerm -> TTerm -> TTerm
TLet (Integer -> TTerm -> TTerm
tNegPlusK (Integer
k forall a. Num a => a -> a -> a
+ Integer
1) (Int -> TTerm
TVar forall a b. (a -> b) -> a -> b
$ Int
e forall a. Num a => a -> a -> a
+ Int
1)) TTerm
b
negsucBranch TAlt
_ = forall a. HasCallStack => a
__IMPOSSIBLE__
TACon QName
c Int
a TTerm
b -> [QName -> Int -> TTerm -> TAlt
TACon QName
c Int
a (TTerm -> TTerm
tr TTerm
b)]
TALit Literal
l TTerm
b -> [Literal -> TTerm -> TAlt
TALit Literal
l (TTerm -> TTerm
tr TTerm
b)]
TAGuard TTerm
g TTerm
b -> [TTerm -> TTerm -> TAlt
TAGuard (TTerm -> TTerm
tr TTerm
g) (TTerm -> TTerm
tr TTerm
b)]
t :: TTerm
t@TVar{} -> TTerm
t
t :: TTerm
t@TDef{} -> TTerm
t
t :: TTerm
t@TCon{} -> TTerm
t
t :: TTerm
t@TPrim{} -> TTerm
t
t :: TTerm
t@TLit{} -> TTerm
t
t :: TTerm
t@TUnit{} -> TTerm
t
t :: TTerm
t@TSort{} -> TTerm
t
t :: TTerm
t@TErased{} -> TTerm
t
t :: TTerm
t@TError{} -> TTerm
t
TCoerce TTerm
a -> TTerm -> TTerm
TCoerce (TTerm -> TTerm
tr TTerm
a)
TLam TTerm
b -> TTerm -> TTerm
TLam (TTerm -> TTerm
tr TTerm
b)
TApp TTerm
a [TTerm]
bs -> TTerm -> [TTerm] -> TTerm
TApp (TTerm -> TTerm
tr TTerm
a) (forall a b. (a -> b) -> [a] -> [b]
map TTerm -> TTerm
tr [TTerm]
bs)
TLet TTerm
e TTerm
b -> TTerm -> TTerm -> TTerm
TLet (TTerm -> TTerm
tr TTerm
e) (TTerm -> TTerm
tr TTerm
b)
inferCaseType :: CaseInfo -> [TAlt] -> CaseInfo
inferCaseType CaseInfo
t (TACon QName
c Int
_ TTerm
_ : [TAlt]
_)
| QName -> Bool
isZero QName
c = CaseInfo
t { caseType :: CaseType
caseType = CaseType
CTNat }
| QName -> Bool
isSuc QName
c = CaseInfo
t { caseType :: CaseType
caseType = CaseType
CTNat }
| QName -> Bool
isPos QName
c = CaseInfo
t { caseType :: CaseType
caseType = CaseType
CTInt }
| QName -> Bool
isNegSuc QName
c = CaseInfo
t { caseType :: CaseType
caseType = CaseType
CTInt }
inferCaseType CaseInfo
t [TAlt]
_ = CaseInfo
t
nPlusKView :: TAlt -> Maybe (Integer, TTerm)
nPlusKView (TAGuard (TApp (TPrim TPrim
PGeq) [TVar Int
0, (TLit (LitNat Integer
k))])
(TLet (TApp (TPrim TPrim
PSub) [TVar Int
0, (TLit (LitNat Integer
j))]) TTerm
b))
| Integer
k forall a. Eq a => a -> a -> Bool
== Integer
j = forall a. a -> Maybe a
Just (Integer
k, TTerm
b)
nPlusKView TAlt
_ = forall a. Maybe a
Nothing