1{-# LANGUAGE PatternGuards #-}
2module Idris.Prover where
4import Idris.Core.Elaborate hiding (Tactic(..))
6import Idris.Core.Evaluate
7import Idris.Core.CaseTree
8import Idris.Core.Typecheck
10import Idris.Elab.Utils
11import Idris.Elab.Value
14import Idris.AbsSyntaxTree
15import Idris.Delaborate
16import Idris.Docs (getDocs, pprintDocs, pprintConstDocs)
19import Idris.Parser hiding (params)
22import Idris.Completion
23import qualified Idris.IdeMode as IdeMode
25import Idris.TypeSearch (searchByType)
27import Text.Trifecta.Result(Result(..))
29import System.IO (Handle, stdin, stdout, hPutStrLn)
30import System.Console.Haskeline
31import System.Console.Haskeline.History
32import Control.Monad.State.Strict
38prover :: Bool -> Name -> Idris ()
42 case lookupTy x ctxt of
43 [t] -> if elem x (map fst (idris_metavars i))
44 then prove (idris_optimisation i) ctxt lit x t
45 else ifail $ show x ++ " is not a metavariable"
46 _ -> fail "No such metavariable"
48showProof :: Bool -> Name -> [String] -> String
50 = bird ++ show n ++ " = proof" ++ break ++
51 showSep break (map (\x -> " " ++ x) ps) ++
53 where bird = if lit then "> " else ""
56proverSettings :: ElabState EState -> Settings Idris
57proverSettings e = setComplete (proverCompletion (assumptionNames e)) defaultSettings
59assumptionNames :: ElabState EState -> [String]
61 = case envAtFocus (proof e) of
64 names ((MN _ _, _) : bs) = names bs
65 names ((n, _) : bs) = show n : names bs
67prove :: Ctxt OptInfo -> Context -> Bool -> Name -> Type -> Idris ()
68prove opt ctxt lit n ty
69 = do let ps = initElaborator n ctxt ty
70 idemodePutSExp "start-proof-mode" n
71 (tm, prf) <- ploop n True ("-" ++ show n) [] (ES (ps, initEState) "" Nothing) Nothing
72 iLOG $ "Adding " ++ show tm
74 case idris_outputmode i of
75 IdeMode _ _ -> idemodePutSExp "end-proof-mode" (n, showProof lit n prf)
76 _ -> iputStrLn $ showProof lit n prf
77 let proofs = proof_list i
78 putIState (i { proof_list = (n, prf) : proofs })
79 let tree = simpleCase False (STerm Erased) False CompileTime (fileFC "proof") [] [] [([], P Ref n ty, tm)]
81 (ptm, pty) <- recheckC (fileFC "proof") id [] tm
82 logLvl 5 ("Proof type: " ++ show pty ++ "\n" ++
83 "Expected type:" ++ show ty)
84 case converts ctxt [] ty pty of
86 Error e -> ierror (CantUnify False (ty, Nothing) (pty, Nothing) e [] 0)
88 ei <- getErasureInfo `fmap` getIState
89 updateContext (addCasedef n ei (CaseInfo True True False) False (STerm Erased) True False
90 [] [] -- argtys, inaccArgs
91 [Right (P Ref n ty, ptm)]
92 [([], P Ref n ty, ptm)]
93 [([], P Ref n ty, ptm)]
94 [([], P Ref n ty, ptm)]
95 [([], P Ref n ty, ptm')] ty)
97 case idris_outputmode i of
99 runIO . hPutStrLn h $ IdeMode.convSExp "return" (IdeMode.SymbolAtom "ok", "") n
102elabStep :: ElabState EState -> ElabD a -> Idris (a, ElabState EState)
103elabStep st e = case runStateT eCheck st of
104 OK (a, st') -> return (a, st')
106 where eCheck = do res <- e
111 [] -> do tm <- get_term
113 lift $ check ctxt [] (forget tm)
115 ((_,_,_,_,e,_,_):_) -> lift $ Error e
117dumpState :: IState -> ProofState -> Idris ()
118dumpState ist ps | [] <- holes ps =
119 do let nm = thname ps
120 rendered <- iRender $ prettyName True False [] nm <> colon <+> text "No more goals."
122dumpState ist ps | (h : hs) <- holes ps = do
123 let OK ty = goalAtFocus ps
124 let OK env = envAtFocus ps
125 let state = prettyOtherGoals hs <> line <>
126 prettyAssumptions env <> line <>
127 prettyGoal (zip (assumptionNames env) (repeat False)) ty
128 rendered <- iRender state
132 (h : hs) = holes ps -- apparently the pattern guards don't give us this
134 ppo = ppOptionIst ist
136 tPretty bnd t = annotate (AnnTerm bnd t) .
137 pprintPTerm ppo bnd [] (idris_infixes ist) $
140 assumptionNames :: Env -> [Name]
141 assumptionNames = map fst
143 prettyPs :: [(Name, Bool)] -> Env -> Doc OutputAnnotation
144 prettyPs bnd [] = empty
145 prettyPs bnd ((n@(MN _ r), _) : bs)
146 | r == txt "rewrite_rule" = prettyPs ((n, False):bnd) bs
147 prettyPs bnd ((n@(MN _ _), _) : bs)
148 | not (n `elem` freeEnvNames bs) = prettyPs bnd bs
149 prettyPs bnd ((n, Let t v) : bs) =
150 line <> bindingOf n False <+> text "=" <+> tPretty bnd v <+> colon <+>
151 align (tPretty bnd t) <> prettyPs ((n, False):bnd) bs
152 prettyPs bnd ((n, b) : bs) =
153 line <> bindingOf n False <+> colon <+>
154 align (tPretty bnd (binderTy b)) <> prettyPs ((n, False):bnd) bs
156 prettyG bnd (Guess t v) = tPretty bnd t <+> text "=?=" <+> tPretty bnd v
157 prettyG bnd b = tPretty bnd $ binderTy b
160 text "---------- Goal: ----------" <$$>
161 bindingOf h False <+> colon <+> align (prettyG bnd ty)
163 prettyAssumptions env =
164 if length env == 0 then
167 text "---------- Assumptions: ----------" <>
168 nest nestingSize (prettyPs [] $ reverse env)
170 prettyOtherGoals hs =
171 if length hs == 0 then
174 text "---------- Other goals: ----------" <$$>
175 nest nestingSize (align . cat . punctuate (text ",") . map (flip bindingOf False) $ hs)
177 freeEnvNames :: Env -> [Name]
178 freeEnvNames = foldl (++) [] . map (\(n, b) -> freeNames (Bind n b Erased))
180lifte :: ElabState EState -> ElabD a -> Idris a
181lifte st e = do (v, _) <- elabStep st e
184receiveInput :: Handle -> ElabState EState -> Idris (Maybe String)
187 let inh = if h == stdout then stdin else h
188 len' <- runIO $ IdeMode.getLen inh
190 Left err -> ierror err
192 l <- runIO $ IdeMode.getNChar inh len ""
193 (sexp, id) <- case IdeMode.parseMessage l of
194 Left err -> ierror err
195 Right (sexp, id) -> return (sexp, id)
196 putIState $ i { idris_outputmode = (IdeMode id h) }
197 case IdeMode.sexpToCommand sexp of
198 Just (IdeMode.REPLCompletions prefix) ->
199 do (unused, compls) <- proverCompletion (assumptionNames e) (reverse prefix, "")
200 let good = IdeMode.SexpList [IdeMode.SymbolAtom "ok", IdeMode.toSExp (map replacement compls, reverse unused)]
201 idemodePutSExp "return" good
203 Just (IdeMode.Interpret cmd) -> return (Just cmd)
204 Just (IdeMode.TypeOf str) -> return (Just (":t " ++ str))
205 Just (IdeMode.DocsFor str _) -> return (Just (":doc " ++ str))
208ploop :: Name -> Bool -> String -> [String] -> ElabState EState -> Maybe History -> Idris (Term, [String])
209ploop fn d prompt prf e h
211 let autoSolve = opt_autoSolve (idris_options i)
212 when d $ dumpState i (proof e)
214 case idris_outputmode i of
216 runInputT (proverSettings e) $
217 -- Manually track the history so that we can use the proof state
219 Just history -> putHistory history
221 l <- getInputLine (prompt ++ "> ")
226 i <- receiveInput handle e
228 (cmd, step) <- case x of
229 Nothing -> do iPrintError ""; ifail "Abandoned"
230 Just input -> do return (parseTactic i input, input)
232 Success Abandon -> do iPrintError ""; ifail "Abandoned"
234 (d, st, done, prf', res) <- idrisCatch
236 Failure err -> return (False, e, False, prf, Left . Msg . show . fixColour (idris_colourRepl i) $ err)
237 Success Undo -> do (_, st) <- elabStep e loadState
238 return (True, st, False, init prf, Right $ iPrintResult "")
239 Success ProofState -> return (True, e, False, prf, Right $ iPrintResult "")
240 Success ProofTerm -> do tm <- lifte e get_term
241 iputStrLn $ "TT: " ++ show tm ++ "\n"
242 return (False, e, False, prf, Right $ iPrintResult "")
243 Success Qed -> do hs <- lifte e get_holes
244 when (not (null hs)) $ ifail "Incomplete proof"
245 iputStrLn "Proof completed!"
246 return (False, e, True, prf, Right $ iPrintResult "")
247 Success (TCheck (PRef _ n)) -> checkNameType n
248 Success (TCheck t) -> checkType t
249 Success (TEval t) -> evalTerm t e
250 Success (TDocStr x) -> docStr x
251 Success (TSearch t) -> search t
253 do (_, e) <- elabStep e saveState
254 (_, st) <- elabStep e (runTac autoSolve i (Just proverFC) fn tac)
255 return (True, st, False, prf ++ [step], Right $ iPrintResult ""))
256 (\err -> return (False, e, False, prf, Left err))
257 idemodePutSExp "write-proof-state" (prf', length prf')
259 Left err -> do ist <- getIState
260 iRenderError $ pprintErr ist err
261 ploop fn d prompt prf' st h'
263 if done then do (tm, _) <- elabStep st get_term
266 ploop fn d prompt prf' st h'
267 where envCtxt env ctxt = foldl (\c (n, b) -> addTyDecl n Bound (binderTy b) c) ctxt env
273 let OK env = envAtFocus (proof e)
274 ctxt' = envCtxt env ctxt
275 bnd = map (\x -> (fst x, False)) env
276 ist' = ist { tt_ctxt = ctxt' }
278 -- Unlike the REPL, metavars have no special treatment, to
279 -- make it easier to see how to prove with them.
280 let action = case lookupNames n ctxt' of
281 [] -> iPrintError $ "No such variable " ++ show n
282 ts -> iPrintFunTypes bnd n (map (\n -> (n, pprintDelabTy ist' n)) ts)
284 return (False, e, False, prf, Right action))
285 (\err -> do putIState ist ; ierror err)
291 let OK env = envAtFocus (proof e)
292 ctxt' = envCtxt env ctxt
293 putIState ist { tt_ctxt = ctxt' }
294 (tm, ty) <- elabVal recinfo ERHS t
295 let ppo = ppOptionIst ist
296 ty' = normaliseC ctxt [] ty
297 infixes = idris_infixes ist
300 iPrintTermWithType (prettyImp ppo PType) type1Doc
301 _ -> let bnd = map (\x -> (fst x, False)) env in
302 iPrintTermWithType (pprintPTerm ppo bnd [] infixes (delab ist tm))
303 (pprintPTerm ppo bnd [] infixes (delab ist ty))
305 return (False, e, False, prf, Right action))
306 (\err -> do putIState ist { tt_ctxt = ctxt } ; ierror err)
308 proverFC = FC "(prover shell)" (0, 0) (0, 0)
310 evalTerm t e = withErrorReflection $
311 do ctxt <- getContext
314 let OK env = envAtFocus (proof e)
315 ctxt' = envCtxt env ctxt
316 ist' = ist { tt_ctxt = ctxt' }
317 bnd = map (\x -> (fst x, False)) env
319 (tm, ty) <- elabVal recinfo ERHS t
320 let tm' = force (normaliseAll ctxt' env tm)
321 ty' = force (normaliseAll ctxt' env ty)
322 ppo = ppOption (idris_options ist')
323 infixes = idris_infixes ist
324 tmDoc = pprintPTerm ppo bnd [] infixes (delab ist' tm')
325 tyDoc = pprintPTerm ppo bnd [] infixes (delab ist' ty')
326 action = iPrintTermWithType tmDoc tyDoc
328 return (False, e, False, prf, Right action))
329 (\err -> do putIState ist ; ierror err)
330 docStr :: Either Name Const -> Idris (Bool, ElabState EState, Bool, [String], Either Err (Idris ()))
331 docStr (Left n) = do ist <- getIState
332 idrisCatch (case lookupCtxtName n (idris_docstrings ist) of
333 [] -> return (False, e, False, prf,
334 Left . Msg $ "No documentation for " ++ show n)
335 ns -> do toShow <- mapM (showDoc ist) ns
336 return (False, e, False, prf,
337 Right $ iRenderResult (vsep toShow)))
338 (\err -> do putIState ist ; ierror err)
339 where showDoc ist (n, d) = do doc <- getDocs n FullDocs
340 return $ pprintDocs ist doc
341 docStr (Right c) = do ist <- getIState
342 return (False, e, False, prf, Right . iRenderResult $ pprintConstDocs ist c (constDocs c))
343 search t = return (False, e, False, prf, Right $ searchByType [] t)
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list