module Idris.ElabDecls where
import Idris.AbsSyntax
import Idris.ASTUtils
import Idris.DSL
import Idris.Error
import Idris.Delaborate
import Idris.Directives
import Idris.Imports
import Idris.Elab.Term
import Idris.Coverage
import Idris.DataOpts
import Idris.Providers
import Idris.Primitives
import Idris.Inliner
import Idris.PartialEval
import Idris.DeepSeq
import Idris.Output (iputStrLn, pshow, iWarn, sendHighlighting)
import IRTS.Lang
import Idris.Elab.Utils
import Idris.Elab.Type
import Idris.Elab.Clause
import Idris.Elab.Data
import Idris.Elab.Record
import Idris.Elab.Class
import Idris.Elab.Instance
import Idris.Elab.Provider
import Idris.Elab.RunElab
import Idris.Elab.Transform
import Idris.Elab.Value
import Idris.Core.TT
import Idris.Core.Elaborate hiding (Tactic(..))
import Idris.Core.Evaluate
import Idris.Core.Execute
import Idris.Core.Typecheck
import Idris.Core.CaseTree
import Idris.Docstrings hiding (Unchecked)
import Prelude hiding (id, (.))
import Control.Category
import Control.Applicative hiding (Const)
import Control.DeepSeq
import Control.Monad
import Control.Monad.State.Strict as State
import Data.List
import Data.Maybe
import Debug.Trace
import qualified Data.Map as Map
import qualified Data.Set as S
import qualified Data.Text as T
import Data.Char(isLetter, toLower)
import Data.List.Split (splitOn)
import Util.Pretty(pretty, text)
recinfo :: ElabInfo
recinfo = EInfo [] emptyContext id Nothing Nothing id elabDecl'
elabMain :: Idris Term
elabMain = do (m, _) <- elabVal recinfo ERHS
(PApp fc (PRef fc [] (sUN "run__IO"))
[pexp $ PRef fc [] (sNS (sUN "main") ["Main"])])
return m
where fc = fileFC "toplevel"
elabPrims :: Idris ()
elabPrims = do mapM_ (elabDecl' EAll recinfo)
(map (\(opt, decl, docs, argdocs) -> PData docs argdocs defaultSyntax (fileFC "builtin") opt decl)
(zip4
[inferOpts, eqOpts]
[inferDecl, eqDecl]
[emptyDocstring, eqDoc]
[[], eqParamDoc]))
addNameHint eqTy (sUN "prf")
mapM_ elabPrim primitives
elabBelieveMe
elabSynEq
where elabPrim :: Prim -> Idris ()
elabPrim (Prim n ty i def sc tot)
= do updateContext (addOperator n ty i (valuePrim def))
setTotality n tot
i <- getIState
putIState i { idris_scprims = (n, sc) : idris_scprims i }
valuePrim :: ([Const] -> Maybe Const) -> [Value] -> Maybe Value
valuePrim prim vals = fmap VConstant (mapM getConst vals >>= prim)
getConst (VConstant c) = Just c
getConst _ = Nothing
p_believeMe [_,_,x] = Just x
p_believeMe _ = Nothing
believeTy = Bind (sUN "a") (Pi Nothing (TType (UVar (2))) (TType (UVar (1))))
(Bind (sUN "b") (Pi Nothing (TType (UVar (2))) (TType (UVar (1))))
(Bind (sUN "x") (Pi Nothing (V 1) (TType (UVar (1)))) (V 1)))
elabBelieveMe
= do let prim__believe_me = sUN "prim__believe_me"
updateContext (addOperator prim__believe_me believeTy 3 p_believeMe)
setTotality prim__believe_me (Total [])
i <- getIState
putIState i {
idris_scprims = (prim__believe_me, (3, LNoOp)) : idris_scprims i
}
p_synEq [t,_,x,y]
| x == y = Just (VApp (VApp vnJust VErased)
(VApp (VApp vnRefl t) x))
| otherwise = Just (VApp vnNothing VErased)
p_synEq args = Nothing
nMaybe = P (TCon 0 2) (sNS (sUN "Maybe") ["Maybe", "Prelude"]) Erased
vnJust = VP (DCon 1 2 False) (sNS (sUN "Just") ["Maybe", "Prelude"]) VErased
vnNothing = VP (DCon 0 1 False) (sNS (sUN "Nothing") ["Maybe", "Prelude"]) VErased
vnRefl = VP (DCon 0 2 False) eqCon VErased
synEqTy = Bind (sUN "a") (Pi Nothing (TType (UVar (3))) (TType (UVar (2))))
(Bind (sUN "b") (Pi Nothing (TType (UVar (3))) (TType (UVar (2))))
(Bind (sUN "x") (Pi Nothing (V 1) (TType (UVar (2))))
(Bind (sUN "y") (Pi Nothing (V 1) (TType (UVar (2))))
(mkApp nMaybe [mkApp (P (TCon 0 4) eqTy Erased)
[V 3, V 2, V 1, V 0]]))))
elabSynEq
= do let synEq = sUN "prim__syntactic_eq"
updateContext (addOperator synEq synEqTy 4 p_synEq)
setTotality synEq (Total [])
i <- getIState
putIState i {
idris_scprims = (synEq, (4, LNoOp)) : idris_scprims i
}
elabDecls :: ElabInfo -> [PDecl] -> Idris ()
elabDecls info ds = do mapM_ (elabDecl EAll info) ds
elabDecl :: ElabWhat -> ElabInfo -> PDecl -> Idris ()
elabDecl what info d
= let info' = info { rec_elabDecl = elabDecl' } in
idrisCatch (withErrorReflection $ elabDecl' what info' d) (setAndReport)
elabDecl' _ info (PFix _ _ _)
= return ()
elabDecl' _ info (PSyntax _ p)
= return ()
elabDecl' what info (PTy doc argdocs s f o n nfc ty)
| what /= EDefns
= do logElab 1 $ "Elaborating type decl " ++ show n ++ show o
elabType info s doc argdocs f o n nfc ty
return ()
elabDecl' what info (PPostulate b doc s f nfc o n ty)
| what /= EDefns
= do logElab 1 $ "Elaborating postulate " ++ show n ++ show o
if b
then elabExtern info s doc f nfc o n ty
else elabPostulate info s doc f nfc o n ty
elabDecl' what info (PData doc argDocs s f co d)
| what /= ETypes
= do logElab 1 $ "Elaborating " ++ show (d_name d)
elabData info s doc argDocs f co d
| otherwise
= do logElab 1 $ "Elaborating [type of] " ++ show (d_name d)
elabData info s doc argDocs f co (PLaterdecl (d_name d) (d_name_fc d) (d_tcon d))
elabDecl' what info d@(PClauses f o n ps)
| what /= ETypes
= do logElab 1 $ "Elaborating clause " ++ show n
i <- getIState
let o' = case lookupCtxt n (idris_flags i) of
[fs] -> fs
[] -> []
elabClauses info f (o ++ o') n ps
elabDecl' what info (PMutual f ps)
= do case ps of
[p] -> elabDecl what info p
_ -> do mapM_ (elabDecl ETypes info) ps
mapM_ (elabDecl EDefns info) ps
let datans = concatMap declared (getDataDecls ps)
mapM_ (setMutData datans) datans
logElab 1 $ "Rechecking for positivity " ++ show datans
mapM_ (\x -> do setTotality x Unchecked) datans
i <- get
mapM_ (\n -> do logElab 5 $ "Simplifying " ++ show n
ctxt' <- do ctxt <- getContext
tclift $ simplifyCasedef n (getErasureInfo i) ctxt
setContext ctxt')
(map snd (idris_totcheck i))
mapM_ buildSCG (idris_totcheck i)
mapM_ checkDeclTotality (idris_totcheck i)
clear_totcheck
where isDataDecl (PData _ _ _ _ _ _) = True
isDataDecl _ = False
getDataDecls (PNamespace _ _ ds : decls)
= getDataDecls ds ++ getDataDecls decls
getDataDecls (d : decls)
| isDataDecl d = d : getDataDecls decls
| otherwise = getDataDecls decls
getDataDecls [] = []
setMutData ns n
= do i <- getIState
case lookupCtxt n (idris_datatypes i) of
[x] -> do let x' = x { mutual_types = ns }
putIState $ i { idris_datatypes
= addDef n x' (idris_datatypes i) }
_ -> return ()
elabDecl' what info (PParams f ns ps)
= do i <- getIState
logElab 1 $ "Expanding params block with " ++ show ns ++ " decls " ++
show (concatMap tldeclared ps)
let nblock = pblock i
mapM_ (elabDecl' what info) nblock
where
pinfo = let ds = concatMap tldeclared ps
newps = params info ++ ns
dsParams = map (\n -> (n, map fst newps)) ds
newb = addAlist dsParams (inblock info) in
info { params = newps,
inblock = newb }
pblock i = map (expandParamsD False i id ns
(concatMap tldeclared ps)) ps
elabDecl' what info (POpenInterfaces f ns ds)
= do open <- addOpenImpl ns
mapM_ (elabDecl' what info) ds
setOpenImpl open
elabDecl' what info (PNamespace n nfc ps) =
do mapM_ (elabDecl' what ninfo) ps
let ns = reverse (map T.pack newNS)
sendHighlighting [(nfc, AnnNamespace ns Nothing)]
where
newNS = maybe [n] (n:) (namespace info)
ninfo = info { namespace = Just newNS }
elabDecl' what info (PClass doc s f cs n nfc ps pdocs fds ds cn cd)
| what /= EDefns
= do logElab 1 $ "Elaborating class " ++ show n
elabClass info (s { syn_params = [] }) doc f cs n nfc ps pdocs fds ds cn cd
elabDecl' what info (PInstance doc argDocs s f cs pnames acc fnopts n nfc ps pextra t expn ds)
= do logElab 1 $ "Elaborating instance " ++ show n
elabInstance info s doc argDocs what f cs pnames acc fnopts n nfc ps pextra t expn ds
elabDecl' what info (PRecord doc rsyn fc opts name nfc ps pdocs fs cname cdoc csyn)
= do logElab 1 $ "Elaborating record " ++ show name
elabRecord info what doc rsyn fc opts name nfc ps pdocs fs cname cdoc csyn
elabDecl' _ info (PDSL n dsl)
= do i <- getIState
putIState (i { idris_dsls = addDef n dsl (idris_dsls i) })
addIBC (IBCDSL n)
elabDecl' what info (PDirective i)
| what /= EDefns = directiveAction i
elabDecl' what info (PProvider doc syn fc nfc provWhat n)
| what /= EDefns
= do logElab 1 $ "Elaborating type provider " ++ show n
elabProvider doc info syn fc nfc provWhat n
elabDecl' what info (PTransform fc safety old new)
= do elabTransform info fc safety old new
return ()
elabDecl' what info (PRunElabDecl fc script ns)
= do elabRunElab info fc script ns
return ()
elabDecl' _ _ _ = return ()