/- Copyright (c) 2020 Microsoft Corporation. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Leonardo de Moura -/ import Lean.Util.RecDepth import Lean.Util.Trace import Lean.Environment import Lean.Exception import Lean.InternalExceptionId import Lean.Eval import Lean.MonadEnv import Lean.ResolveName namespace Lean namespace Core structure State where env : Environment nextMacroScope : MacroScope := firstFrontendMacroScope + 1 ngen : NameGenerator := {} traceState : TraceState := {} instance : Inhabited State := ⟨{ env := arbitrary }⟩ structure Context where options : Options := {} currRecDepth : Nat := 0 maxRecDepth : Nat := 1000 ref : Syntax := Syntax.missing currNamespace : Name := Name.anonymous openDecls : List OpenDecl := [] abbrev CoreM := ReaderT Context $ StateRefT State (EIO Exception) instance : Inhabited (CoreM α) := ⟨fun _ _ => throw arbitrary⟩ instance : MonadRef CoreM := { getRef := do let ctx ← read; pure ctx.ref, withRef := fun ref x => withReader (fun ctx => { ctx with ref := ref }) x } instance : MonadEnv CoreM := { getEnv := do pure (← get).env, modifyEnv := fun f => modify fun s => { s with env := f s.env } } instance : MonadOptions CoreM := { getOptions := do pure (← read).options } instance : AddMessageContext CoreM := { addMessageContext := addMessageContextPartial } instance : MonadNameGenerator CoreM := { getNGen := do pure (← get).ngen, setNGen := fun ngen => modify fun s => { s with ngen := ngen } } instance : MonadRecDepth CoreM := { withRecDepth := fun d x => withReader (fun ctx => { ctx with currRecDepth := d }) x, getRecDepth := do pure (← read).currRecDepth, getMaxRecDepth := do pure (← read).maxRecDepth } instance : MonadResolveName CoreM := { getCurrNamespace := do pure (← read).currNamespace, getOpenDecls := do pure (← read).openDecls } @[inline] def liftIOCore (x : IO α) : CoreM α := do let ref ← getRef IO.toEIO (fun (err : IO.Error) => Exception.error ref (toString err)) x instance : MonadLift IO CoreM := { monadLift := liftIOCore } instance : MonadTrace CoreM := { getTraceState := do pure (← get).traceState, modifyTraceState := fun f => modify fun s => { s with traceState := f s.traceState } } private def mkFreshNameImp (n : Name) : CoreM Name := do let fresh ← modifyGet fun s => (s.nextMacroScope, { s with nextMacroScope := s.nextMacroScope + 1 }) let env ← getEnv pure $ addMacroScope env.mainModule n fresh def mkFreshUserName [MonadLiftT CoreM m] (n : Name) : m Name := liftM $ mkFreshNameImp n @[inline] def CoreM.run (x : CoreM α) (ctx : Context) (s : State) : EIO Exception (α × State) := (x ctx).run s @[inline] def CoreM.run' (x : CoreM α) (ctx : Context) (s : State) : EIO Exception α := Prod.fst <$> x.run ctx s @[inline] def CoreM.toIO (x : CoreM α) (ctx : Context) (s : State) : IO (α × State) := do match (← (x.run ctx s).toIO') with | Except.error (Exception.error _ msg) => do let e ← msg.toString; throw $ IO.userError e | Except.error (Exception.internal id _) => throw $ IO.userError $ "internal exception #" ++ toString id.idx | Except.ok a => pure a instance [MetaEval α] : MetaEval (CoreM α) := { eval := fun env opts x _ => do let x : CoreM α := do try x finally printTraces let (a, s) ← x.toIO { maxRecDepth := getMaxRecDepth opts, options := opts } { env := env } MetaEval.eval s.env opts a (hideUnit := true) } -- withIncRecDepth for a monad `m` such that `[MonadControlT CoreM n]` protected def withIncRecDepth [Monad m] [MonadControlT CoreM m] (x : m α) : m α := controlAt CoreM fun runInBase => withIncRecDepth (runInBase x) end Core export Core (CoreM mkFreshUserName) @[inline] def catchInternalId [Monad m] [MonadExcept Exception m] (id : InternalExceptionId) (x : m α) (h : Exception → m α) : m α := do try x catch ex => match ex with | Exception.error _ _ => throw ex | Exception.internal id' _ => if id == id' then h ex else throw ex @[inline] def catchInternalIds [Monad m] [MonadExcept Exception m] (ids : List InternalExceptionId) (x : m α) (h : Exception → m α) : m α := do try x catch ex => match ex with | Exception.error _ _ => throw ex | Exception.internal id _ => if ids.contains id then h ex else throw ex end Lean