forked from leanprover/lean4
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathMainM.lean
90 lines (67 loc) · 2.84 KB
/
MainM.lean
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
/-
Copyright (c) 2021 Mac Malone. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Mac Malone
-/
import Lake.Util.Log
import Lake.Util.Exit
import Lake.Util.Error
import Lake.Util.Lift
namespace Lake
/--
The monad in Lake for `main`-like functions.
Supports IO, logging, and `exit`.
-/
def MainM := EIO ExitCode
instance : Monad MainM := inferInstanceAs (Monad (EIO ExitCode))
instance : MonadFinally MainM := inferInstanceAs (MonadFinally (EIO ExitCode))
instance : MonadLift BaseIO MainM := inferInstanceAs (MonadLift BaseIO (EIO ExitCode))
namespace MainM
/-! # Basics -/
@[inline] protected def mk (x : EIO ExitCode α) : MainM α :=
x
@[inline] protected def toEIO (self : MainM α) : EIO ExitCode α :=
self
@[inline] protected def toBaseIO (self : MainM α) : BaseIO (Except ExitCode α) :=
self.toEIO.toBaseIO
@[inline] protected def run (self : MainM α) : BaseIO ExitCode :=
self.toBaseIO.map fun | Except.ok _ => 0 | Except.error rc => rc
/-! # Exits -/
/-- Exit with given return code. -/
@[inline] protected def exit (rc : ExitCode) : MainM α :=
MainM.mk <| throw rc
instance : MonadExit MainM := ⟨MainM.exit⟩
/-- Try this and catch exits. -/
@[inline] protected def tryCatchExit (f : ExitCode → MainM α) (self : MainM α) : MainM α :=
self.toEIO.tryCatch f
/-- Try this and catch error codes (i.e., non-zero exits). -/
@[inline] protected def tryCatchError (f : ExitCode → MainM α) (self : MainM α) : MainM α :=
self.tryCatchExit fun rc => if rc = 0 then exit 0 else f rc
/-- Exit with a generic error code (i.e., 1). -/
@[inline] protected def failure : MainM α :=
exit 1
/-- If this exits with an error code (i.e., not 0), perform other. -/
@[inline] protected def orElse (self : MainM α) (other : Unit → MainM α) : MainM α :=
self.tryCatchExit fun rc => if rc = 0 then exit 0 else other ()
instance : Alternative MainM where
failure := MainM.failure
orElse := MainM.orElse
/-! # Logging and IO -/
instance : MonadLog MainM := .stderr
/-- Print out a error line with the given message and then exit with an error code. -/
@[inline] protected def error (msg : String) (rc : ExitCode := 1) : MainM α := do
logError msg
exit rc
instance : MonadError MainM := ⟨MainM.error⟩
instance : MonadLift IO MainM := ⟨MonadError.runIO⟩
@[inline] def runLogIO (x : LogIO α)
(minLv := LogLevel.info) (ansiMode := AnsiMode.auto) (out := OutStream.stderr)
: MainM α := do
match (← x {}) with
| .ok a log => replay log (← out.getLogger minLv ansiMode); return a
| .error _ log => replay log (← out.getLogger .trace ansiMode); exit 1
where
-- avoid specialization of this call at each call site
replay (log : Log) (logger : MonadLog BaseIO) : BaseIO Unit :=
log.replay (logger := logger)
instance (priority := low) : MonadLift LogIO MainM := ⟨runLogIO⟩