lean4-htt/library/Init/Lean/Trace.lean
2019-11-18 19:54:05 -08:00

164 lines
5.7 KiB
Text
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/-
Copyright (c) 2018 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Sebastian Ullrich, Leonardo de Moura
-/
prelude
import Init.Lean.Message
universe u
namespace Lean
class MonadTracer (m : Type → Type u) :=
(traceCtx {α} : Name → m α → m α)
(trace {} : Name → (Unit → MessageData) → m PUnit)
class MonadTracerAdapter (m : Type → Type) :=
(isTracingEnabledFor {} : Name → m Bool)
(enableTracing {} : Bool → m Unit)
(getTraces {} : m (Array MessageData))
(modifyTraces {} : (Array MessageData → Array MessageData) → m Unit)
namespace MonadTracerAdapter
section
variables {m : Type → Type}
variables [Monad m] [MonadTracerAdapter m]
variables {α : Type}
private def addNode (oldTraces : Array MessageData) (cls : Name) : m Unit :=
modifyTraces $ fun traces =>
let d := MessageData.tagged cls (MessageData.node traces);
oldTraces.push d
private def getResetTraces : m (Array MessageData) :=
do oldTraces ← getTraces;
modifyTraces $ fun _ => #[];
pure oldTraces
private def addTrace (cls : Name) (msg : MessageData) : m Unit :=
modifyTraces $ fun traces => traces.push (MessageData.tagged cls msg)
@[inline] protected def trace (cls : Name) (msg : Unit → MessageData) : m Unit :=
whenM (isTracingEnabledFor cls) (addTrace cls (msg ()))
@[inline] def traceCtx (cls : Name) (ctx : m α) : m α :=
do b ← isTracingEnabledFor cls;
if !b then do enableTracing true; a ← ctx; enableTracing false; pure a
else do
oldCurrTraces ← getResetTraces;
a ← ctx;
addNode oldCurrTraces cls;
pure a
end
section
variables {ε : Type} {m : Type → Type}
variables [MonadExcept ε m] [Monad m] [MonadTracerAdapter m]
variables {α : Type}
/- Version of `traceCtx` with exception handling support. -/
@[inline] protected def traceCtxExcept (cls : Name) (ctx : m α) : m α :=
do b ← isTracingEnabledFor cls;
if !b then do
enableTracing true;
catch
(do a ← ctx; enableTracing false; pure a)
(fun e => do enableTracing false; throw e)
else do
oldCurrTraces ← getResetTraces;
catch
(do a ← ctx; addNode oldCurrTraces cls; pure a)
(fun e => do addNode oldCurrTraces cls; throw e)
end
end MonadTracerAdapter
instance monadTracerAdapter {m : Type → Type} [Monad m] [MonadTracerAdapter m] : MonadTracer m :=
{ traceCtx := @MonadTracerAdapter.traceCtx _ _ _,
trace := @MonadTracerAdapter.trace _ _ _ }
instance monadTracerAdapterExcept {ε : Type} {m : Type → Type} [Monad m] [MonadExcept ε m] [MonadTracerAdapter m] : MonadTracer m :=
{ traceCtx := @MonadTracerAdapter.traceCtxExcept _ _ _ _ _,
trace := @MonadTracerAdapter.trace _ _ _ }
structure TraceState :=
(enabled : Bool := true)
(traces : Array MessageData := #[])
namespace TraceState
instance : Inhabited TraceState := ⟨{}⟩
instance : HasFormat TraceState := ⟨fun s => Format.joinArraySep s.traces Format.line⟩
instance : HasToString TraceState := ⟨toString ∘ fmt⟩
end TraceState
class SimpleMonadTracerAdapter (m : Type → Type) :=
(getOptions {} : m Options)
(modifyTraceState {} : (TraceState → TraceState) → m Unit)
(getTraceState {} : m TraceState)
namespace SimpleMonadTracerAdapter
variables {m : Type → Type} [Monad m] [SimpleMonadTracerAdapter m]
private def checkTraceOptionAux (opts : Options) : Name → Bool
| n@(Name.str p _ _) => opts.getBool n || (!opts.contains n && checkTraceOptionAux p)
| _ => false
private def checkTraceOption (optName : Name) : m Bool :=
do opts ← getOptions;
if opts.isEmpty then pure false
else pure $ checkTraceOptionAux opts optName
@[inline] def isTracingEnabledFor (cls : Name) : m Bool :=
do s ← getTraceState;
if !s.enabled then pure false
else checkTraceOption (`trace ++ cls)
@[inline] def enableTracing (b : Bool) : m Unit :=
modifyTraceState $ fun s => { enabled := b, .. s }
@[inline] def getTraces : m (Array MessageData) :=
do s ← getTraceState; pure s.traces
@[inline] def modifyTraces (f : Array MessageData → Array MessageData) : m Unit :=
modifyTraceState $ fun s => { traces := f s.traces, .. s }
end SimpleMonadTracerAdapter
instance simpleMonadTracerAdapter {m : Type → Type} [SimpleMonadTracerAdapter m] [Monad m] : MonadTracerAdapter m :=
{ isTracingEnabledFor := @SimpleMonadTracerAdapter.isTracingEnabledFor _ _ _,
enableTracing := @SimpleMonadTracerAdapter.enableTracing _ _ _,
getTraces := @SimpleMonadTracerAdapter.getTraces _ _ _,
modifyTraces := @SimpleMonadTracerAdapter.modifyTraces _ _ _ }
export MonadTracer (traceCtx trace)
/-
Recipe for adding tracing support for a monad `M`.
1- Define the instance `SimpleMonadTracerAdapter M` by showing how to retrieve `Options` and
get/modify `TraceState` object.
2- The `Options` control whether tracing commands are ignored or not.
3- The macro `trace! <cls> <msg>` adds the trace message `<msg>` if `<cls>` is activate and tracing is enabled.
4- We activate the tracing class `<cls>` by setting option `trace.<cls>` to true. If a prefix `p` of `trace.<cls>` is
set to true, and there isn't a longer prefix `p'` set to false, then `<cls>` is also considered active.
5- `traceCtx <cls> <action>` groups all messages generated by `<action>` into a single `MessageData.node`.
If `<cls> is not activate, then (all) tracing is disabled while executing `<action>`. This feature is
useful for the following scenario:
a) We have a tactic called `mysimp` which uses trace class `mysimp`.
b) `mysimp invokes the unifier module which uses trace class `unify`.
c) In the beginning of `mysimp`, we use `traceCtx`.
In this scenario, by not enabling `mysimp` we also disable the `unify` trace messages produced
by executing `mysimp`.
-/
end Lean