1{-# LANGUAGE MultiParamTypeClasses, FlexibleInstances, DeriveFunctor,
11import Idris.Delaborate
14import Idris.Primitives
16import Idris.UnusedArgs
19import Idris.Completion
20import qualified Idris.IdeSlave as IdeSlave
29import Version_idris (gitHash)
31import Util.DynamicLinker
32import Util.Net (listenOnLocalhost)
34import Idris.Core.Evaluate
35import Idris.Core.Execute (execute)
37import Idris.Core.Constraints
40import IRTS.CodegenCommon
42import Text.Trifecta.Result(Result(..))
49import LLVM.General.Target
53import System.Console.Haskeline as H
56import System.Environment
58import System.Directory
61import Control.Monad.Trans.Error (ErrorT(..))
62import Control.Monad.Trans.State.Strict ( StateT, execStateT, evalStateT, get, put )
63import Control.Monad.Trans ( lift )
64import Control.Concurrent.MVar
66import Control.Concurrent
71import Data.Word (Word)
74import qualified Text.PrettyPrint.ANSI.Leijen as ANSI
79repl :: IState -- ^ The initial state
80 -> [FilePath] -- ^ The loaded modules
84 (do let quiet = opt_quiet (idris_options orig)
86 let colour = idris_colourRepl i
87 let theme = idris_colourTheme i
88 let mvs = idris_metavars i
91 else showMVs colour theme mvs ++
92 let str = mkPrompt mods ++ ">" in
93 (if colour then colourisePrompt theme str else str) ++ " "
94 x <- getInputLine prompt
96 Nothing -> do lift $ when (not quiet) (iputStrLn "Bye bye")
99 (do ms <- lift $ processInput input orig mods
101 Just mods -> repl orig mods
102 Nothing -> return ())
105 where ctrlC :: SomeException -> InputT Idris ()
106 ctrlC e = do lift $ iputStrLn (show e)
109 showMVs c thm [] = ""
110 showMVs c thm ms = "Metavariables: " ++
111 show' 4 c thm (map fst ms) ++ "\n"
113 show' 0 c thm ms = let l = length ms in
116 ++ if l == 1 then ")" else "s)"
117 show' n c thm [m] = showM c thm m
118 show' n c thm (m : ms) = showM c thm m ++ ", " ++
119 show' (n - 1) c thm ms
121 showM c thm n = if c then colouriseFun thm (show n)
124-- | Run the REPL server
125startServer :: IState -> [FilePath] -> Idris ()
126startServer orig fn_in = do tid <- runIO $ forkOS serverLoop
128 where serverLoop :: IO ()
129 -- TODO: option for port number
130 serverLoop = withSocketsDo $
131 do sock <- listenOnLocalhost $ PortNumber 4294
139 = do (h,host,_) <- accept sock
140 -- just use the local part of the hostname
141 -- for the "localhost.localdomain" case
142 if ((takeWhile (/= '.') host) == "localhost" ||
146 (ist', fn) <- processNetCmd orig ist h fn cmd
150 putStrLn $ "Closing connection attempt from non-localhost " ++ host
153processNetCmd :: IState -> IState -> Handle -> FilePath -> String ->
154 IO (IState, FilePath)
155processNetCmd orig i h fn cmd
156 = do res <- case parseCmd i "(net)" cmd of
157 Failure err -> return (Left (Msg " invalid command"))
158 Success c -> runErrorT $ evalStateT (processNet fn c) i
161 Left err -> do hPutStrLn h (show err)
164 processNet fn Reload = processNet fn (Load fn)
165 processNet fn (Load f) =
166 do let ist = orig { idris_options = idris_options i
167 , idris_colourTheme = idris_colourTheme i
168 , idris_colourRepl = False
175 mods <- loadInputs h [f]
178 processNet fn c = do process h fn c
182-- | Run a command on the server on localhost
183runClient :: String -> IO ()
184runClient str = withSocketsDo $ do
185 h <- connectTo "localhost" (PortNumber 4294)
187 resp <- hGetResp "" h
190 where hGetResp acc h = do eof <- hIsEOF h
191 if eof then return acc
192 else do l <- hGetLine h
193 hGetResp (acc ++ l ++ "\n") h
196ideslaveStart :: IState -> [FilePath] -> Idris ()
197ideslaveStart orig mods
199 case idris_outputmode i of
201 when (mods /= []) (do isetPrompt (mkPrompt mods))
205ideslave :: IState -> [FilePath] -> Idris ()
208 (do l <- runIO $ getLine
209 (sexp, id) <- case IdeSlave.parseMessage l of
210 Left err -> ierror err
211 Right (sexp, id) -> return (sexp, id)
213 putIState $ i { idris_outputmode = (IdeSlave id) }
214 idrisCatch -- to report correct id back!
215 (do let fn = case mods of
218 case IdeSlave.sexpToCommand sexp of
219 Just (IdeSlave.Interpret cmd) ->
221 case parseCmd i "(input)" cmd of
222 Failure err -> iPrintError $ show (fixColour c err)
223 Success (Prove n') -> do iPrintResult ""
225 (process stdout fn (Prove n'))
226 (\e -> getIState >>= iPrintError . flip pshow e)
227 isetPrompt (mkPrompt mods)
228 Success cmd -> idrisCatch
229 (ideslaveProcess fn cmd)
230 (\e -> getIState >>= iPrintError . flip pshow e)
231 Just (IdeSlave.REPLCompletions str) ->
232 do (unused, compls) <- replCompletion (reverse str, "")
233 let good = IdeSlave.SexpList [IdeSlave.SymbolAtom "ok", IdeSlave.toSExp (map replacement compls, reverse unused)]
234 runIO $ putStrLn $ IdeSlave.convSExp "return" good id
235 Just (IdeSlave.LoadFile filename) ->
237 putIState (orig { idris_options = idris_options i,
238 idris_outputmode = (IdeSlave id) })
239 loadInputs stdout [filename]
240 isetPrompt (mkPrompt [filename])
241 -- Report either success or failure
244 Nothing -> iPrintResult $ "loaded " ++ filename
245 Just x -> iPrintError $ "didn't load " ++ filename
246 ideslave orig [filename]
247 Just (IdeSlave.TypeOf name) ->
248 process stdout "(ideslave)" (Check (PRef (FC "(ideslave)" 0 0) (UN name)))
249 Just (IdeSlave.CaseSplit line name) ->
250 process stdout fn (CaseSplitAt False line (UN name))
251 Just (IdeSlave.AddClause line name) ->
252 process stdout fn (AddClauseFrom False line (UN name))
253 Just (IdeSlave.AddProofClause line name) ->
254 process stdout fn (AddProofClauseFrom False line (UN name))
255 Just (IdeSlave.AddMissing line name) ->
256 process stdout fn (AddMissing False line (UN name))
257 Just (IdeSlave.MakeWithBlock line name) ->
258 process stdout fn (MakeWith False line (UN name))
259 Just (IdeSlave.ProofSearch line name hints) ->
260 process stdout fn (DoProofSearch False line (UN name) (map UN hints))
261 Nothing -> do iPrintError "did not understand")
262 (\e -> do iPrintError $ show e))
263 (\e -> do iPrintError $ show e)
266ideslaveProcess :: FilePath -> Command -> Idris ()
267ideslaveProcess fn Help = process stdout fn Help
268ideslaveProcess fn (ChangeDirectory f) = do process stdout fn (ChangeDirectory f)
269 iPrintResult "changed directory to"
270ideslaveProcess fn (Eval t) = process stdout fn (Eval t)
271ideslaveProcess fn (ExecVal t) = process stdout fn (ExecVal t)
272ideslaveProcess fn (Check (PRef x n)) = process stdout fn (Check (PRef x n))
273ideslaveProcess fn (Check t) = process stdout fn (Check t)
274ideslaveProcess fn (DocStr n) = process stdout fn (DocStr n)
275ideslaveProcess fn Universes = process stdout fn Universes
276ideslaveProcess fn (Defn n) = do process stdout fn (Defn n)
278ideslaveProcess fn (TotCheck n) = process stdout fn (TotCheck n)
279ideslaveProcess fn (DebugInfo n) = do process stdout fn (DebugInfo n)
281ideslaveProcess fn (Info n) = process stdout fn (Info n)
282ideslaveProcess fn (Search t) = process stdout fn (Search t)
283ideslaveProcess fn (Spec t) = process stdout fn (Spec t)
284-- RmProof and AddProof not supported!
285ideslaveProcess fn (ShowProof n') = process stdout fn (ShowProof n')
286ideslaveProcess fn (HNF t) = process stdout fn (HNF t)
287--ideslaveProcess fn TTShell = process stdout fn TTShell -- need some prove mode!
288ideslaveProcess fn (TestInline t) = process stdout fn (TestInline t)
290--that most likely does not work, since we need to wrap
291--input/output of the executed binary...
292ideslaveProcess fn Execute = do process stdout fn Execute
294ideslaveProcess fn (Compile codegen f) = do process stdout fn (Compile codegen f)
296ideslaveProcess fn (LogLvl i) = do process stdout fn (LogLvl i)
298ideslaveProcess fn (Pattelab t) = process stdout fn (Pattelab t)
299ideslaveProcess fn (Missing n) = process stdout fn (Missing n)
300ideslaveProcess fn (DynamicLink l) = do process stdout fn (DynamicLink l)
302ideslaveProcess fn ListDynamic = do process stdout fn ListDynamic
304ideslaveProcess fn Metavars = process stdout fn Metavars
305ideslaveProcess fn (SetOpt ErrContext) = do process stdout fn (SetOpt ErrContext)
307ideslaveProcess fn (UnsetOpt ErrContext) = do process stdout fn (UnsetOpt ErrContext)
309ideslaveProcess fn (SetOpt ShowImpl) = do process stdout fn (SetOpt ShowImpl)
311ideslaveProcess fn (UnsetOpt ShowImpl) = do process stdout fn (UnsetOpt ShowImpl)
313ideslaveProcess fn (SetOpt x) = process stdout fn (SetOpt x)
314ideslaveProcess fn (UnsetOpt x) = process stdout fn (UnsetOpt x)
315ideslaveProcess fn (CaseSplitAt False pos str) = process stdout fn (CaseSplitAt False pos str)
316ideslaveProcess fn (AddProofClauseFrom False pos str) = process stdout fn (AddProofClauseFrom False pos str)
317ideslaveProcess fn (AddClauseFrom False pos str) = process stdout fn (AddClauseFrom False pos str)
318ideslaveProcess fn (AddMissing False pos str) = process stdout fn (AddMissing False pos str)
319ideslaveProcess fn (MakeWith False pos str) = process stdout fn (MakeWith False pos str)
320ideslaveProcess fn (DoProofSearch False pos str xs) = process stdout fn (DoProofSearch False pos str xs)
321ideslaveProcess fn _ = iPrintError "command not recognized or not supported"
324-- | The prompt consists of the currently loaded modules, or "Idris" if there are none
326mkPrompt [x] = "*" ++ dropExtension x
327mkPrompt (x:xs) = "*" ++ dropExtension x ++ " " ++ mkPrompt xs
329-- | Determine whether a file uses literate syntax
330lit f = case splitExtension f of
334processInput :: String ->
335 IState -> [FilePath] -> Idris (Maybe [FilePath])
336processInput cmd orig inputs
338 let opts = idris_options i
339 let quiet = opt_quiet opts
340 let fn = case inputs of
344 case parseCmd i "(input)" cmd of
345 Failure err -> do runIO $ print (fixColour c err)
348 do putIState $ orig { idris_options = idris_options i
349 , idris_colourTheme = idris_colourTheme i
352 mods <- loadInputs stdout inputs
355 do putIState orig { idris_options = idris_options i
356 , idris_colourTheme = idris_colourTheme i
359 mod <- loadInputs stdout [f]
361 Success (ModImport f) ->
363 fmod <- loadModule stdout f
364 return (Just (inputs ++ [fmod]))
365 Success Edit -> do -- takeMVar stvar
368 Success Proofs -> do proofs orig
370 Success Quit -> do when (not quiet) (iputStrLn "Bye bye")
372 Success cmd -> do idrisCatch (process stdout fn cmd)
373 (\e -> do msg <- showErr e ; iputStrLn msg)
376resolveProof :: Name -> Idris Name
380 n <- case lookupNames n' ctxt of
383 ns -> ierror (CantResolveAlts (map show ns))
386removeProof :: Name -> Idris ()
389 let proofs = proof_list i
390 let ps = filter ((/= n) . fst) proofs
391 putIState $ i { proof_list = ps }
393edit :: FilePath -> IState -> Idris ()
394edit "" orig = iputStrLn "Nothing to edit"
397 env <- runIO $ getEnvironment
398 let editor = getEditor env
399 let line = case errLine i of
400 Just l -> " +" ++ show l ++ " "
402 let cmd = editor ++ line ++ fixName f
405 putIState $ orig { idris_options = idris_options i
406 , idris_colourTheme = idris_colourTheme i
408 loadInputs stdout [f]
411 where getEditor env | Just ed <- lookup "EDITOR" env = ed
412 | Just ed <- lookup "VISUAL" env = ed
414 fixName file | map toLower (takeExtension file) `elem` [".lidr", ".idr"] = file
415 | otherwise = addExtension file "idr"
419proofs :: IState -> Idris ()
422 let ps = proof_list i
424 [] -> iputStrLn "No proofs available"
425 _ -> iputStrLn $ "Proofs:\n\t" ++ (show $ map fst ps)
427insertScript :: String -> [String] -> [String]
428insertScript prf [] = "\n---------- Proofs ----------" : "" : [prf]
429insertScript prf (p@"---------- Proofs ----------" : "" : xs)
431insertScript prf (x : xs) = x : insertScript prf xs
433process :: Handle -> FilePath -> Command -> Idris ()
434process h fn Help = iPrintResult displayHelp
435process h fn (ChangeDirectory f)
436 = do runIO $ setCurrentDirectory f
439 = do (tm, ty) <- elabVal toplevel False t
441 let tm' = force (normaliseAll ctxt [] tm)
442 let ty' = force (normaliseAll ctxt [] ty)
443 -- Add value to context, call it "it"
444 updateContext (addCtxtDef (UN "it") (Function ty' tm'))
446 logLvl 3 $ "Raw: " ++ show (tm', ty')
447 logLvl 10 $ "Debug: " ++ showEnvDbg [] tm'
450 ihPrintResult h (showImp (Just ist) imp c (delab ist tm') ++ " : " ++
451 showImp (Just ist) imp c (delab ist ty'))
452process h fn (ExecVal t)
453 = do ctxt <- getContext
455 (tm, ty) <- elabVal toplevel False t
456-- let tm' = normaliseAll ctxt [] tm
457 let ty' = normaliseAll ctxt [] ty
461 ihPrintResult h (showImp (Just ist) imp c (delab ist res) ++ " : " ++
462 showImp (Just ist) imp c (delab ist ty'))
463process h fn (Check (PRef _ n))
464 = do ctxt <- getContext
468 case lookupNames n ctxt of
470 case lookup t (idris_metavars ist) of
471 Just (_, i, _) -> ihPrintResult h (showMetavarInfo c imp ist n i)
472 Nothing -> ihPrintResult h $
473 concat . intersperse "\n" . map (\n -> showName (Just ist) [] False c n ++ " : " ++
474 showImp (Just ist) imp c (delabTy ist n)) $ ts
475 [] -> ihPrintError h $ "No such variable " ++ show n
477 showMetavarInfo c imp ist n i
478 = case lookupTy n (tt_ctxt ist) of
479 (ty:_) -> putTy c imp ist i (delab ist ty)
480 putTy c imp ist 0 sc = putGoal c imp ist sc
481 putTy c imp ist i (PPi _ n t sc)
482 = let current = " " ++
485 UN ('_':'_':_) -> "_"
486 _ -> showName (Just ist) [] False c n) ++
487 " : " ++ showImp (Just ist) imp c t ++ "\n"
489 current ++ putTy c imp ist (i-1) sc
490 putTy c imp ist _ sc = putGoal c imp ist sc
492 = "--------------------------------------\n" ++
493 showName (Just ist) [] False c n ++ " : " ++
494 showImp (Just ist) imp c g
497process h fn (Check t)
498 = do (tm, ty) <- elabVal toplevel False t
503 let ty' = normaliseC ctxt [] ty
505 TType _ -> ihPrintResult h ("Type : Type 1")
506 _ -> ihPrintResult h (showImp (Just ist) imp c (delab ist tm) ++ " : " ++
507 showImp (Just ist) imp c (delab ist ty))
509process h fn (DocStr n)
511 case lookupCtxtName n (idris_docstrings i) of
512 [] -> iPrintError $ "No documentation for " ++ show n
513 ns -> do mapM_ showDoc ns
516 = do doc <- getDocs n
518process h fn Universes
520 let cs = idris_constraints i
521-- iputStrLn $ showSep "\n" (map show cs)
522 iputStrLn $ show (map fst cs)
524 iputStrLn $ "(" ++ show n ++ " constraints)"
526 Error e -> iPrintError $ pshow i e
527 OK _ -> iPrintResult "Universes OK"
530 iputStrLn "Compiled patterns:\n"
531 iputStrLn $ show (lookupDef n (tt_ctxt i))
532 case lookupCtxt n (idris_patdefs i) of
534 [(d, _)] -> do iputStrLn "Original definiton:\n"
535 mapM_ (printCase i) d
536 case lookupTotal n (tt_ctxt i) of
537 [t] -> iputStrLn (showTotal t i)
539 where printCase i (_, lhs, rhs)
541 iputStrLn (showImp (Just i) True c (delab i lhs) ++ " = " ++
542 showImp (Just i) True c (delab i rhs))
543process h fn (TotCheck n)
545 case lookupNameTotal n (tt_ctxt i) of
546 [] -> ihPrintError h $ "Unknown operator " ++ show n
547 ts -> do ist <- getIState
550 let showN = showName (Just ist) [] imp c
551 ihPrintResult h . concat . intersperse "\n" .
552 map (\(n, t) -> showN n ++ " is " ++ showTotal t i) $
556process h fn (DebugInfo n)
558 let oi = lookupCtxtName n (idris_optimisation i)
559 when (not (null oi)) $ iputStrLn (show oi)
560 let si = lookupCtxt n (idris_statics i)
561 when (not (null si)) $ iputStrLn (show si)
562 let di = lookupCtxt n (idris_datatypes i)
563 when (not (null di)) $ iputStrLn (show di)
564 let d = lookupDef n (tt_ctxt i)
565 when (not (null d)) $ iputStrLn $ "Definition: " ++ (show (head d))
566 let cg = lookupCtxtName n (idris_callgraph i)
567 findUnusedArgs (map fst cg)
569 let cg' = lookupCtxtName n (idris_callgraph i)
570 sc <- checkSizeChange n
571 iputStrLn $ "Size change: " ++ show sc
572 when (not (null cg')) $ do iputStrLn "Call graph:\n"
576 case lookupCtxt n (idris_classes i) of
578 _ -> iPrintError "Not a class"
579process h fn (Search t) = iPrintError "Not implemented"
580-- FIXME: There is far too much repetition in the cases below!
581process h fn (CaseSplitAt updatefile l n)
582 = do src <- runIO $ readFile fn
583 res <- splitOnLine l n fn
584 iLOG (showSep "\n" (map show res))
585 let (before, (ap : later)) = splitAt (l-1) (lines src)
586 res' <- replaceSplits ap res
587 let new = concat res'
589 then do let fb = fn ++ "~" -- make a backup!
590 runIO $ writeFile fb (unlines before ++ new ++ unlines later)
591 runIO $ copyFile fb fn
592 else -- do ihputStrLn h (show res)
594process h fn (AddClauseFrom updatefile l n)
595 = do src <- runIO $ readFile fn
596 let (before, tyline : later) = splitAt (l-1) (lines src)
597 let indent = getIndent 0 (show n) tyline
598 cl <- getClause l n fn
599 -- add clause before first blank line in 'later'
600 let (nonblank, rest) = span (not . all isSpace) (tyline:later)
602 then do let fb = fn ++ "~"
603 runIO $ writeFile fb (unlines (before ++ nonblank) ++
604 replicate indent ' ' ++
607 runIO $ copyFile fb fn
608 else ihPrintResult h cl
611 getIndent i n xs | take (length n) xs == n = i
612 getIndent i n (x : xs) = getIndent (i + 1) n xs
613process h fn (AddProofClauseFrom updatefile l n)
614 = do src <- runIO $ readFile fn
615 let (before, tyline : later) = splitAt (l-1) (lines src)
616 let indent = getIndent 0 (show n) tyline
617 cl <- getProofClause l n fn
618 -- add clause before first blank line in 'later'
619 let (nonblank, rest) = span (not . all isSpace) (tyline:later)
621 then do let fb = fn ++ "~"
622 runIO $ writeFile fb (unlines (before ++ nonblank) ++
623 replicate indent ' ' ++
626 runIO $ copyFile fb fn
627 else ihPrintResult h cl
630 getIndent i n xs | take (length n) xs == n = i
631 getIndent i n (x : xs) = getIndent (i + 1) n xs
632process h fn (AddMissing updatefile l n)
633 = do src <- runIO $ readFile fn
634 let (before, tyline : later) = splitAt (l-1) (lines src)
635 let indent = getIndent 0 (show n) tyline
637 cl <- getInternalApp fn l
638 let n' = getAppName cl
640 extras <- case lookupCtxt n' (idris_patdefs i) of
642 [(_, tms)] -> do tms' <- nameMissing tms
643 showNew (show n ++ "_rhs") 1 indent tms'
644 let (nonblank, rest) = span (not . all isSpace) (tyline:later)
646 then do let fb = fn ++ "~"
647 runIO $ writeFile fb (unlines (before ++ nonblank)
648 ++ extras ++ unlines rest)
649 runIO $ copyFile fb fn
650 else ihPrintResult h extras
651 where showPat = show . stripNS
652 stripNS tm = mapPT dens tm where
653 dens (PRef fc n) = PRef fc (nsroot n)
656 nsroot (NS n _) = nsroot n
657 nsroot (SN (WhereN _ _ n)) = nsroot n
660 getAppName (PApp _ r _) = getAppName r
661 getAppName (PRef _ r) = r
664 showNew nm i ind (tm : tms)
665 = do (nm', i') <- getUniq nm i
666 rest <- showNew nm i' ind tms
667 return (replicate ind ' ' ++
668 showPat tm ++ " = ?" ++ nm' ++
670 showNew nm i _ [] = return ""
673 getIndent i n xs | take (length n) xs == n = i
674 getIndent i n (x : xs) = getIndent (i + 1) n xs
676process h fn (MakeWith updatefile l n)
677 = do src <- runIO $ readFile fn
678 let (before, tyline : later) = splitAt (l-1) (lines src)
679 let ind = getIndent tyline
680 let with = mkWith tyline n
681 -- add clause before first blank line in 'later',
682 -- or (TODO) before first line with same indentation as tyline
683 let (nonblank, rest) = span (\x -> not (all isSpace x) &&
684 not (ind == getIndent x)) later
686 do let fb = fn ++ "~"
687 runIO $ writeFile fb (unlines (before ++ nonblank)
690 runIO $ copyFile fb fn
691 else ihPrintResult h with
692 where getIndent s = length (takeWhile isSpace s)
694process h fn (DoProofSearch updatefile l n hints)
695 = do src <- runIO $ readFile fn
696 let (before, tyline : later) = splitAt (l-1) (lines src)
698 mn <- case lookupNames n ctxt of
701 ns -> ierror (CantResolveAlts (map show ns))
703 let (top, envlen, _) = case lookup mn (idris_metavars i) of
704 Just (t, e, False) -> (t, e, False)
705 _ -> (Nothing, 0, True)
707 let body t = PProof [Try (TSeq Intros (ProofSearch t n hints))
708 (ProofSearch t n hints)]
709 let def = PClause fc mn (PRef fc mn) [] (body top) []
711 (do elabDecl' EAll toplevel (PClauses fc [] mn [def])
712 (tm, ty) <- elabVal toplevel False (PRef fc mn)
715 return $ show (stripNS
717 (delab i (specialise ctxt [] [(mn, 1)] tm)))))
718 (\e -> return ("?" ++ show n))
720 do let fb = fn ++ "~"
721 runIO $ writeFile fb (unlines before ++
722 updateMeta False tyline (show n) newmv ++ "\n"
724 runIO $ copyFile fb fn
725 else ihPrintResult h newmv
726 where dropCtxt 0 sc = sc
727 dropCtxt i (PPi _ _ _ sc) = dropCtxt (i - 1) sc
728 dropCtxt i (PLet _ _ _ sc) = dropCtxt (i - 1) sc
729 dropCtxt i (PLam _ _ sc) = dropCtxt (i - 1) sc
732 stripNS tm = mapPT dens tm where
733 dens (PRef fc n) = PRef fc (nsroot n)
736 nsroot (NS n _) = nsroot n
737 nsroot (SN (WhereN _ _ n)) = nsroot n
740 updateMeta brack ('?':cs) n new
741 | length cs >= length n
742 = case splitAt (length n) cs of
744 if (isSpace c && mv == n)
745 then addBracket brack new ++ (c : cs)
746 else '?' : mv ++ c : updateMeta True cs n new
747 (mv, []) -> if (mv == n) then addBracket brack new else '?' : mv
748 updateMeta brack ('=':cs) n new = '=':updateMeta False cs n new
749 updateMeta brack (c:cs) n new
750 = c : updateMeta (brack || not (isSpace c)) cs n new
751 updateMeta brack [] n new = ""
753 addBracket False new = new
754 addBracket True new@('(':xs) | last xs == ')' = new
755 addBracket True new | any isSpace new = '(' : new ++ ")"
759 = do (tm, ty) <- elabVal toplevel False t
762 let tm' = simplify ctxt [] {- (idris_statics ist) -} tm
763 iPrintResult (show (delab ist tm'))
765process h fn (RmProof n')
768 let proofs = proof_list i
769 case lookup n proofs of
770 Nothing -> iputStrLn "No proof to remove"
771 Just _ -> do removeProof n
773 iputStrLn $ "Removed proof " ++ show n
775 insertMetavar :: Name -> Idris ()
778 let ms = idris_metavars i
779 putIState $ i { idris_metavars = (n, (Nothing, 0, False)) : ms }
781process h fn' (AddProof prf)
783 ex <- runIO $ doesFileExist fn'
784 let fnExt = fn' <.> "idr"
785 exExt <- runIO $ doesFileExist fnExt
790 else ifail $ "Neither \""++fn'++"\" nor \""++fnExt++"\" exist"
792 runIO $ copyFile fn fb -- make a backup in case something goes wrong!
793 prog <- runIO $ readFile fb
795 let proofs = proof_list i
797 Nothing -> case proofs of
798 [] -> ifail "No proof to add"
799 ((x, p) : _) -> return x
802 case lookup n proofs of
803 Nothing -> iputStrLn "No proof to add"
804 Just p -> do let prog' = insertScript (showProof (lit fn) n p) ls
805 runIO $ writeFile fn (unlines prog')
807 iputStrLn $ "Added proof " ++ show n
808 where ls = (lines prog)
810process h fn (ShowProof n')
813 let proofs = proof_list i
814 case lookup n proofs of
815 Nothing -> iPrintError "No proof to show"
816 Just p -> iPrintResult $ showProof False n p
818process h fn (Prove n')
819 = do ctxt <- getContext
821 let ns = lookupNames n' ctxt
822 let metavars = mapMaybe (\n -> do c <- lookup n (idris_metavars ist); return (n, c)) ns
823 n <- case metavars of
824 [] -> ierror (Msg $ "Cannot find metavariable " ++ show n')
825 [(n, (_,_,False))] -> return n
826 [(_, (_,_,True))] -> ierror (Msg $ "Declarations not solvable using prover")
827 ns -> ierror (CantResolveAlts (map show ns))
831 totcheck (fileFC "(input)", n)
832 mapM_ (\ (f,n) -> setTotality n Unchecked) (idris_totcheck i)
833 mapM_ checkDeclTotality (idris_totcheck i)
836 = do (tm, ty) <- elabVal toplevel False t
839 let tm' = hnf ctxt [] tm
840 iPrintResult (show (delab ist tm'))
841process h fn (TestInline t)
842 = do (tm, ty) <- elabVal toplevel False t
845 let tm' = inlineTerm ist tm
848 iPrintResult (showImp (Just ist) imp c (delab ist tm'))
850 = do (m, _) <- elabVal toplevel False
852 (PRef fc (UN "run__IO"))
853 [pexp $ PRef fc (NS (UN "main") ["Main"])])
854-- (PRef (FC "main" 0) (NS (UN "main") ["main"]))
855 (tmpn, tmph) <- runIO tempfile
861 where fc = fileFC "main"
862process h fn (Compile codegen f)
863 = do (m, _) <- elabVal toplevel False
864 (PApp fc (PRef fc (UN "run__IO"))
865 [pexp $ PRef fc (NS (UN "main") ["Main"])])
867 where fc = fileFC "main"
868process h fn (LogLvl i) = setLogLevel i
869-- Elaborate as if LHS of a pattern (debug command)
870process h fn (Pattelab t)
871 = do (tm, ty) <- elabVal toplevel True t
872 iPrintResult $ show tm ++ "\n\n : " ++ show ty
874process h fn (Missing n)
877 case lookupCtxt n (idris_patdefs i) of
880 iPrintResult (showSep "\n" (map (showImp (Just i) True c) tms))
881 _ -> iPrintError $ "Ambiguous name"
882process h fn (DynamicLink l)
885 handle <- lift . lift $ tryLoadLib lib
887 Nothing -> iPrintError $ "Could not load dynamic lib \"" ++ l ++ "\""
888 Just x -> do let libs = idris_dynamic_libs i
890 then do iLOG ("Tried to load duplicate library " ++ lib_name x)
892 else putIState $ i { idris_dynamic_libs = x:libs }
893 where trim = reverse . dropWhile isSpace . reverse . dropWhile isSpace
894process h fn ListDynamic
896 iputStrLn "Dynamic libraries:"
897 showLibs $ idris_dynamic_libs i
898 where showLibs [] = return ()
899 showLibs ((Lib name _):ls) = do iputStrLn $ "\t" ++ name; showLibs ls
901 = do ist <- getIState
902 let mvs = map fst (idris_metavars ist) \\ primDefs
904 [] -> iPrintError "No global metavariables to solve"
905 _ -> iPrintResult $ "Global metavariables:\n\t" ++ show mvs
906process h fn NOP = return ()
908process h fn (SetOpt ErrContext) = setErrContext True
909process h fn (UnsetOpt ErrContext) = setErrContext False
910process h fn (SetOpt ShowImpl) = setImpShow True
911process h fn (UnsetOpt ShowImpl) = setImpShow False
913process h fn (SetOpt _) = iPrintError "Not a valid option"
914process h fn (UnsetOpt _) = iPrintError "Not a valid option"
915process h fn (SetColour ty c) = setColour ty c
917 = do ist <- getIState
918 putIState $ ist { idris_colourRepl = True }
919process h fn ColourOff
920 = do ist <- getIState
921 putIState $ ist { idris_colourRepl = False }
923classInfo :: ClassInfo -> Idris ()
924classInfo ci = do iputStrLn "Methods:\n"
925 mapM_ dumpMethod (class_methods ci)
927 iputStrLn "Default superclass instances:\n"
928 mapM_ dumpDefaultInstance (class_default_superclasses ci)
930 iputStrLn "Instances:\n"
931 mapM_ dumpInstance (class_instances ci)
934dumpMethod :: (Name, (FnOpts, PTerm)) -> Idris ()
935dumpMethod (n, (_, t)) = iputStrLn $ show n ++ " : " ++ show t
937dumpDefaultInstance :: PDecl -> Idris ()
938dumpDefaultInstance (PInstance _ _ _ _ _ t _ _) = iputStrLn $ show t
940dumpInstance :: Name -> Idris ()
941dumpInstance n = do i <- getIState
944 case lookupTy n ctxt of
945 ts -> mapM_ (\t -> iputStrLn $ showImp Nothing imp False (delab i t)) ts
947showTotal :: Totality -> IState -> String
948showTotal t@(Partial (Other ns)) i
949 = show t ++ "\n\t" ++ showSep "\n\t" (map (showTotalN i) ns)
950showTotal t i = show t
951showTotalN i n = case lookupTotal n (tt_ctxt i) of
955displayHelp = let vstr = showVersion version in
956 "\nIdris version " ++ vstr ++ "\n" ++
957 "--------------" ++ map (\x -> '-') vstr ++ "\n\n" ++
958 concatMap cmdInfo helphead ++
959 concatMap cmdInfo help
960 where cmdInfo (cmds, args, text) = " " ++ col 16 12 (showSep " " cmds) (show args) text
962 l ++ take (c1 - length l) (repeat ' ') ++
963 m ++ take (c2 - length m) (repeat ' ') ++ r ++ "\n"
965parseCodegen :: String -> Codegen
966parseCodegen "C" = ViaC
967parseCodegen "Java" = ViaJava
968parseCodegen "bytecode" = Bytecode
969parseCodegen "javascript" = ViaJavaScript
970parseCodegen "node" = ViaNode
971parseCodegen "llvm" = ViaLLVM
972parseCodegen _ = error "unknown codegen" -- FIXME: partial function
974parseArgs :: [String] -> [Opt]
976parseArgs ("--nobanner":ns) = NoBanner : (parseArgs ns)
977parseArgs ("--quiet":ns) = Quiet : (parseArgs ns)
978parseArgs ("--ideslave":ns) = Ideslave : (parseArgs ns)
979parseArgs ("--client":ns) = [Client (showSep " " ns)]
980parseArgs ("--log":lvl:ns) = OLogging (read lvl) : (parseArgs ns)
981parseArgs ("--nobasepkgs":ns) = NoBasePkgs : (parseArgs ns)
982parseArgs ("--noprelude":ns) = NoPrelude : (parseArgs ns)
983parseArgs ("--nobuiltins":ns) = NoBuiltins : NoPrelude : (parseArgs ns)
984parseArgs ("--check":ns) = NoREPL : (parseArgs ns)
985parseArgs ("-o":n:ns) = NoREPL : Output n : (parseArgs ns)
986parseArgs ("--typecase":ns) = TypeCase : (parseArgs ns)
987parseArgs ("--typeintype":ns) = TypeInType : (parseArgs ns)
988parseArgs ("--total":ns) = DefaultTotal : (parseArgs ns)
989parseArgs ("--partial":ns) = DefaultPartial : (parseArgs ns)
990parseArgs ("--warnpartial":ns) = WarnPartial : (parseArgs ns)
991parseArgs ("--nocoverage":ns) = NoCoverage : (parseArgs ns)
992parseArgs ("--errorcontext":ns) = ErrContext : (parseArgs ns)
993parseArgs ("--help":ns) = Usage : (parseArgs ns)
994parseArgs ("--link":ns) = ShowLibs : (parseArgs ns)
995parseArgs ("--libdir":ns) = ShowLibdir : (parseArgs ns)
996parseArgs ("--include":ns) = ShowIncs : (parseArgs ns)
997parseArgs ("--version":ns) = Ver : (parseArgs ns)
998parseArgs ("--verbose":ns) = Verbose : (parseArgs ns)
999parseArgs ("--ibcsubdir":n:ns) = IBCSubDir n : (parseArgs ns)
1000parseArgs ("-i":n:ns) = ImportDir n : (parseArgs ns)
1001parseArgs ("--warn":ns) = WarnOnly : (parseArgs ns)
1002parseArgs ("--package":n:ns) = Pkg n : (parseArgs ns)
1003parseArgs ("-p":n:ns) = Pkg n : (parseArgs ns)
1004parseArgs ("--build":n:ns) = PkgBuild n : (parseArgs ns)
1005parseArgs ("--install":n:ns) = PkgInstall n : (parseArgs ns)
1006parseArgs ("--clean":n:ns) = PkgClean n : (parseArgs ns)
1007parseArgs ("--bytecode":n:ns) = NoREPL : BCAsm n : (parseArgs ns)
1008parseArgs ("-S":ns) = OutputTy Raw : (parseArgs ns)
1009parseArgs ("-c":ns) = OutputTy Object : (parseArgs ns)
1010parseArgs ("--mvn":ns) = OutputTy MavenProject : (parseArgs ns)
1011parseArgs ("--dumpdefuns":n:ns) = DumpDefun n : (parseArgs ns)
1012parseArgs ("--dumpcases":n:ns) = DumpCases n : (parseArgs ns)
1013parseArgs ("--codegen":n:ns) = UseCodegen (parseCodegen n) : (parseArgs ns)
1014parseArgs ["--exec"] = InterpretScript "Main.main" : []
1015parseArgs ("--exec":expr:ns) = InterpretScript expr : parseArgs ns
1016parseArgs (('-':'X':extName):ns) = case maybeRead extName of
1017 Just ext -> Extension ext : parseArgs ns
1018 -- Not sure what to do for the Nothing case
1019 Nothing -> error ("Unknown extension " ++ extName)
1020 where maybeRead = fmap fst . listToMaybe . reads
1021parseArgs ("-O3":ns) = OptLevel 3 : parseArgs ns
1022parseArgs ("-O2":ns) = OptLevel 2 : parseArgs ns
1023parseArgs ("-O1":ns) = OptLevel 1 : parseArgs ns
1024parseArgs ("-O0":ns) = OptLevel 0 : parseArgs ns
1025parseArgs ("-O":n:ns) = OptLevel (read n) : parseArgs ns
1026parseArgs ("--target":n:ns) = TargetTriple n : parseArgs ns
1027parseArgs ("--cpu":n:ns) = TargetCPU n : parseArgs ns
1028parseArgs ("--colour":ns) = ColourREPL True : parseArgs ns
1029parseArgs ("--color":ns) = ColourREPL True : parseArgs ns
1030parseArgs ("--nocolour":ns) = ColourREPL False : parseArgs ns
1031parseArgs ("--nocolor":ns) = ColourREPL False : parseArgs ns
1032parseArgs (n:ns) = Filename n : (parseArgs ns)
1035 [ (["Command"], SpecialHeaderArg, "Purpose"),
1040replSettings :: Maybe FilePath -> Settings Idris
1041replSettings hFile = setComplete replCompletion $ defaultSettings {
1045-- invoke as if from command line
1046idris :: [Opt] -> IO (Maybe IState)
1047idris opts = do res <- runErrorT $ execStateT (idrisMain opts) idrisInit
1049 Left err -> do putStrLn $ pshow idrisInit err
1051 Right ist -> return (Just ist)
1054loadInputs :: Handle -> [FilePath] -> Idris ()
1057 (do ist <- getIState
1058 -- if we're in --check and not outputting anything, don't bother
1059 -- loading, as it gets really slow if there's lots of modules in
1060 -- a package (instead, reload all at the end to check for
1061 -- consistency only)
1064 let loadCode = case opt getOutput opts of
1065 [] -> not (NoREPL `elem` opts)
1068 -- For each ifile list, check it and build ibcs in the same clean IState
1069 -- so that they don't interfere with each other when checking
1071 let ninputs = zip [1..] inputs
1072 ifiles <- mapWhileOK (\(num, input) ->
1075 -- when v $ iputStrLn $ "(" ++ show num ++ "/" ++
1076 -- show (length inputs) ++
1078 modTree <- buildTree
1079 (map snd (take (num-1) ninputs))
1081 let ifiles = getModuleFiles modTree
1082 iLOG ("MODULE TREE : " ++ show modTree)
1083 iLOG ("RELOAD: " ++ show ifiles)
1084 when (not (all ibc ifiles) || loadCode) $ tryLoad ifiles
1085 -- return the files that need rechecking
1086 return (if (all ibc ifiles) then ifiles else []))
1089 -- to check everything worked consistently (in particular, will catch
1090 -- if the ibc version is out of date) if we weren't loading per
1092 case errLine inew of
1095 when (not loadCode) $ tryLoad $ nub (concat ifiles)
1099 At f _ -> do setErrLine (fc_line f)
1101 ProgramLineComment -> return () -- fail elsewhere
1102 _ -> do setErrLine 3 -- FIXME! Propagate it
1104 where -- load all files, stop if any fail
1105 tryLoad :: [IFileType] -> Idris ()
1106 tryLoad [] = return ()
1107 tryLoad (f : fs) = do loadFromIFile h f
1109 when ok $ tryLoad fs
1111 ibc (IBC _ _) = True
1114 -- Like mapM, but give up when there's an error
1115 mapWhileOK f [] = return []
1116 mapWhileOK f (x : xs) = do x' <- f x
1118 if ok then do xs' <- mapWhileOK f xs
1122idrisMain :: [Opt] -> Idris ()
1124 do let inputs = opt getFile opts
1125 let quiet = Quiet `elem` opts
1126 let nobanner = NoBanner `elem` opts
1127 let idesl = Ideslave `elem` opts
1128 let runrepl = not (NoREPL `elem` opts)
1129 let verbose = runrepl || Verbose `elem` opts
1130 let output = opt getOutput opts
1131 let ibcsubdir = opt getIBCSubDir opts
1132 let importdirs = opt getImportDir opts
1133 let bcs = opt getBC opts
1134 let pkgdirs = opt getPkgDir opts
1135 let optimize = case opt getOptLevel opts of
1138 trpl <- case opt getTriple opts of
1139 [] -> runIO $ getDefaultTargetTriple
1140 xs -> return (last xs)
1141 tcpu <- case opt getCPU opts of
1142 [] -> runIO $ getHostCPUName
1143 xs -> return (last xs)
1144 let outty = case opt getOutputTy opts of
1147 let cgn = case opt getCodegen opts of
1150 script <- case opt getExecScript opts of
1151 [] -> return Nothing
1152 x:y:xs -> do iputStrLn "More than one interpreter expression found."
1153 runIO $ exitWith (ExitFailure 1)
1154 [expr] -> return (Just expr)
1155 when (DefaultTotal `elem` opts) $ do i <- getIState
1156 putIState (i { default_total = True })
1157 setColourise $ not quiet && last (True : opt getColour opts)
1158 mapM_ addLangExt (opt getLanguageExt opts)
1160 setQuiet (quiet || isJust script)
1166 setTargetTriple trpl
1168 setOptLevel optimize
1169 mapM_ makeOption opts
1170 -- if we have the --bytecode flag, drop into the bytecode assembler
1173 xs -> return () -- runIO $ mapM_ bcAsm xs
1175 [] -> setIBCSubDir ""
1176 (d:_) -> setIBCSubDir d
1177 setImportDirs importdirs
1179 when (not (NoBasePkgs `elem` opts)) $ do
1182 mapM_ addPkgDir pkgdirs
1184 when (not (NoBuiltins `elem` opts)) $ do x <- loadModule stdout "Builtins"
1186 when (not (NoPrelude `elem` opts)) $ do x <- loadModule stdout "Prelude"
1188 when (runrepl && not quiet && not idesl && not (isJust script) && not nobanner) $ iputStrLn banner
1191 loadInputs stdout inputs
1193 runIO $ hSetBuffering stdout LineBuffering
1196 when ok $ case output of
1198 (o:_) -> idrisCatch (process stdout "" (Compile cgn o))
1199 (\e -> do ist <- getIState ; iputStrLn $ pshow ist e)
1201 Nothing -> return ()
1202 Just expr -> execScript expr
1204 -- Create Idris data dir + repl history and config dir
1205 idrisCatch (do dir <- getIdrisUserDataDir
1206 exists <- runIO $ doesDirectoryExist dir
1207 unless exists $ iLOG ("Creating " ++ dir)
1208 runIO $ createDirectoryIfMissing True (dir </> "repl"))
1211 historyFile <- fmap (</> "repl" </> "history") getIdrisUserDataDir
1213 when (runrepl && not idesl) $ do
1215 startServer ist inputs
1216 runInputT (replSettings (Just historyFile)) $ repl ist inputs
1217 when (idesl) $ ideslaveStart ist inputs
1219 when (not ok) $ runIO (exitWith (ExitFailure 1))
1221 makeOption (OLogging i) = setLogLevel i
1222 makeOption TypeCase = setTypeCase True
1223 makeOption TypeInType = setTypeInType True
1224 makeOption NoCoverage = setCoverage False
1225 makeOption ErrContext = setErrContext True
1226 makeOption _ = return ()
1228 addPkgDir :: String -> Idris ()
1229 addPkgDir p = do ddir <- runIO $ getDataDir
1230 addImportDir (ddir </> p)
1232execScript :: String -> Idris ()
1233execScript expr = do i <- getIState
1235 case parseExpr i expr of
1236 Failure err -> do iputStrLn $ show (fixColour c err)
1237 runIO $ exitWith (ExitFailure 1)
1238 Success term -> do ctxt <- getContext
1239 (tm, _) <- elabVal toplevel False term
1241 runIO $ exitWith ExitSuccess
1243-- | Check if the coloring matches the options and corrects if necessary
1244fixColour :: Bool -> ANSI.Doc -> ANSI.Doc
1245fixColour False doc = ANSI.plain doc
1246fixColour True doc = doc
1248-- | Get the platform-specific, user-specific Idris dir
1249getIdrisUserDataDir :: Idris FilePath
1250getIdrisUserDataDir = runIO $ getAppUserDataDirectory "idris"
1252-- | Locate the platform-specific location for the init script
1253getInitScript :: Idris FilePath
1254getInitScript = do idrisDir <- getIdrisUserDataDir
1255 return $ idrisDir </> "repl" </> "init"
1257-- | Run the initialisation script
1258initScript :: Idris ()
1259initScript = do script <- getInitScript
1260 idrisCatch (do go <- runIO $ doesFileExist script
1262 h <- runIO $ openFile script ReadMode
1265 (\e -> iPrintError $ "Error reading init file: " ++ show e)
1266 where runInit :: Handle -> Idris ()
1267 runInit h = do eof <- lift . lift $ hIsEOF h
1270 line <- runIO $ hGetLine h
1271 script <- getInitScript
1273 processLine ist line script c
1275 processLine i cmd input clr =
1276 case parseCmd i input cmd of
1277 Failure err -> runIO $ print (fixColour clr err)
1278 Success Reload -> iPrintError "Init scripts cannot reload the file"
1279 Success (Load f) -> iPrintError "Init scripts cannot load files"
1280 Success (ModImport f) -> iPrintError "Init scripts cannot import modules"
1281 Success Edit -> iPrintError "Init scripts cannot invoke the editor"
1282 Success Proofs -> proofs i
1283 Success Quit -> iPrintError "Init scripts cannot quit Idris"
1284 Success cmd -> process stdout [] cmd
1286getFile :: Opt -> Maybe String
1287getFile (Filename str) = Just str
1290getBC :: Opt -> Maybe String
1291getBC (BCAsm str) = Just str
1294getOutput :: Opt -> Maybe String
1295getOutput (Output str) = Just str
1296getOutput _ = Nothing
1298getIBCSubDir :: Opt -> Maybe String
1299getIBCSubDir (IBCSubDir str) = Just str
1300getIBCSubDir _ = Nothing
1302getImportDir :: Opt -> Maybe String
1303getImportDir (ImportDir str) = Just str
1304getImportDir _ = Nothing
1306getPkgDir :: Opt -> Maybe String
1307getPkgDir (Pkg str) = Just str
1308getPkgDir _ = Nothing
1310getPkg :: Opt -> Maybe (Bool, String)
1311getPkg (PkgBuild str) = Just (False, str)
1312getPkg (PkgInstall str) = Just (True, str)
1315getPkgClean :: Opt -> Maybe String
1316getPkgClean (PkgClean str) = Just str
1317getPkgClean _ = Nothing
1319getCodegen :: Opt -> Maybe Codegen
1320getCodegen (UseCodegen x) = Just x
1321getCodegen _ = Nothing
1323getExecScript :: Opt -> Maybe String
1324getExecScript (InterpretScript expr) = Just expr
1325getExecScript _ = Nothing
1327getOutputTy :: Opt -> Maybe OutputType
1328getOutputTy (OutputTy t) = Just t
1329getOutputTy _ = Nothing
1331getLanguageExt :: Opt -> Maybe LanguageExt
1332getLanguageExt (Extension e) = Just e
1333getLanguageExt _ = Nothing
1335getTriple :: Opt -> Maybe String
1336getTriple (TargetTriple x) = Just x
1337getTriple _ = Nothing
1339getCPU :: Opt -> Maybe String
1340getCPU (TargetCPU x) = Just x
1343getOptLevel :: Opt -> Maybe Word
1344getOptLevel (OptLevel x) = Just x
1345getOptLevel _ = Nothing
1347getColour :: Opt -> Maybe Bool
1348getColour (ColourREPL b) = Just b
1349getColour _ = Nothing
1351opt :: (Opt -> Maybe a) -> [Opt] -> [a]
1354ver = showVersion version ++ gitHash
1356banner = " ____ __ _ \n" ++
1357 " / _/___/ /____(_)____ \n" ++
1358 " / // __ / ___/ / ___/ Version " ++ ver ++ "\n" ++
1359 " _/ // /_/ / / / (__ ) http://www.idris-lang.org/ \n" ++
1360 " /___/\\__,_/_/ /_/____/ Type :? for help \n"
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