2024-11-08 14:49:49 -08:00
|
|
|
|
import Lean.Environment
|
|
|
|
|
import Lean.Replay
|
2024-11-13 19:50:31 -08:00
|
|
|
|
import Init.System.IOError
|
2024-11-08 14:49:49 -08:00
|
|
|
|
import Std.Data.HashMap
|
2024-12-05 14:23:55 -08:00
|
|
|
|
import Pantograph.Goal
|
2024-11-08 14:49:49 -08:00
|
|
|
|
|
|
|
|
|
/-!
|
|
|
|
|
Input/Output functions
|
|
|
|
|
|
|
|
|
|
# Pickling and unpickling objects
|
|
|
|
|
|
|
|
|
|
By abusing `saveModuleData` and `readModuleData` we can pickle and unpickle objects to disk.
|
|
|
|
|
-/
|
|
|
|
|
|
|
|
|
|
open Lean
|
|
|
|
|
|
|
|
|
|
namespace Pantograph
|
|
|
|
|
|
|
|
|
|
/--
|
|
|
|
|
Save an object to disk.
|
|
|
|
|
If you need to write multiple objects from within a single declaration,
|
|
|
|
|
you will need to provide a unique `key` for each.
|
|
|
|
|
-/
|
|
|
|
|
def pickle {α : Type} (path : System.FilePath) (x : α) (key : Name := by exact decl_name%) : IO Unit :=
|
|
|
|
|
saveModuleData path key (unsafe unsafeCast x)
|
|
|
|
|
|
|
|
|
|
/--
|
|
|
|
|
Load an object from disk.
|
|
|
|
|
Note: The returned `CompactedRegion` can be used to free the memory behind the value
|
|
|
|
|
of type `α`, using `CompactedRegion.free` (which is only safe once all references to the `α` are
|
|
|
|
|
released). Ignoring the `CompactedRegion` results in the data being leaked.
|
|
|
|
|
Use `withUnpickle` to call `CompactedRegion.free` automatically.
|
|
|
|
|
|
|
|
|
|
This function is unsafe because the data being loaded may not actually have type `α`, and this
|
|
|
|
|
may cause crashes or other bad behavior.
|
|
|
|
|
-/
|
|
|
|
|
unsafe def unpickle (α : Type) (path : System.FilePath) : IO (α × CompactedRegion) := do
|
|
|
|
|
let (x, region) ← readModuleData path
|
|
|
|
|
pure (unsafeCast x, region)
|
|
|
|
|
|
|
|
|
|
/-- Load an object from disk and run some continuation on it, freeing memory afterwards. -/
|
|
|
|
|
unsafe def withUnpickle [Monad m] [MonadLiftT IO m] {α β : Type}
|
|
|
|
|
(path : System.FilePath) (f : α → m β) : m β := do
|
|
|
|
|
let (x, region) ← unpickle α path
|
|
|
|
|
let r ← f x
|
|
|
|
|
region.free
|
|
|
|
|
pure r
|
|
|
|
|
|
|
|
|
|
/--
|
|
|
|
|
Pickle an `Environment` to disk.
|
|
|
|
|
|
|
|
|
|
We only store:
|
|
|
|
|
* the list of imports
|
|
|
|
|
* the new constants from `Environment.constants`
|
|
|
|
|
and when unpickling, we build a fresh `Environment` from the imports,
|
|
|
|
|
and then add the new constants.
|
|
|
|
|
-/
|
|
|
|
|
@[export pantograph_env_pickle_m]
|
2024-12-04 10:44:33 -08:00
|
|
|
|
def environmentPickle (env : Environment) (path : System.FilePath) : IO Unit :=
|
2024-11-08 14:49:49 -08:00
|
|
|
|
Pantograph.pickle path (env.header.imports, env.constants.map₂)
|
|
|
|
|
|
|
|
|
|
/--
|
|
|
|
|
Unpickle an `Environment` from disk.
|
|
|
|
|
|
|
|
|
|
We construct a fresh `Environment` with the relevant imports,
|
|
|
|
|
and then replace the new constants.
|
|
|
|
|
-/
|
|
|
|
|
@[export pantograph_env_unpickle_m]
|
2024-12-04 10:44:33 -08:00
|
|
|
|
def environmentUnpickle (path : System.FilePath) : IO (Environment × CompactedRegion) := unsafe do
|
2024-11-08 14:49:49 -08:00
|
|
|
|
let ((imports, map₂), region) ← Pantograph.unpickle (Array Import × PHashMap Name ConstantInfo) path
|
|
|
|
|
let env ← importModules imports {} 0
|
|
|
|
|
return (← env.replay (Std.HashMap.ofList map₂.toList), region)
|
|
|
|
|
|
2024-12-05 14:23:55 -08:00
|
|
|
|
|
|
|
|
|
open Lean.Core in
|
|
|
|
|
structure CompactCoreState where
|
|
|
|
|
-- env : Environment
|
|
|
|
|
nextMacroScope : MacroScope := firstFrontendMacroScope + 1
|
|
|
|
|
ngen : NameGenerator := {}
|
|
|
|
|
-- traceState : TraceState := {}
|
|
|
|
|
-- cache : Cache := {}
|
|
|
|
|
-- messages : MessageLog := {}
|
|
|
|
|
-- infoState : Elab.InfoState := {}
|
|
|
|
|
|
|
|
|
|
@[export pantograph_goal_state_pickle_m]
|
|
|
|
|
def goalStatePickle (goalState : GoalState) (path : System.FilePath) : IO Unit :=
|
|
|
|
|
let {
|
|
|
|
|
savedState := {
|
|
|
|
|
term := {
|
|
|
|
|
meta := {
|
|
|
|
|
core,
|
|
|
|
|
meta,
|
|
|
|
|
}
|
|
|
|
|
«elab»,
|
|
|
|
|
},
|
|
|
|
|
tactic
|
|
|
|
|
}
|
|
|
|
|
root,
|
|
|
|
|
parentMVar?,
|
|
|
|
|
convMVar?,
|
|
|
|
|
calcPrevRhs?,
|
|
|
|
|
} := goalState
|
|
|
|
|
--let env := core.env
|
|
|
|
|
Pantograph.pickle path (
|
|
|
|
|
({ core with } : CompactCoreState),
|
|
|
|
|
meta,
|
|
|
|
|
«elab»,
|
|
|
|
|
tactic,
|
|
|
|
|
|
|
|
|
|
root,
|
|
|
|
|
parentMVar?,
|
|
|
|
|
convMVar?,
|
|
|
|
|
calcPrevRhs?,
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
@[export pantograph_goal_state_unpickle_m]
|
|
|
|
|
def goalStateUnpickle (path : System.FilePath) (env : Environment)
|
|
|
|
|
: IO (GoalState × CompactedRegion) := unsafe do
|
|
|
|
|
let ((
|
|
|
|
|
compactCore,
|
|
|
|
|
meta,
|
|
|
|
|
«elab»,
|
|
|
|
|
tactic,
|
|
|
|
|
|
|
|
|
|
root,
|
|
|
|
|
parentMVar?,
|
|
|
|
|
convMVar?,
|
|
|
|
|
calcPrevRhs?,
|
|
|
|
|
), region) ← Pantograph.unpickle (
|
|
|
|
|
CompactCoreState ×
|
|
|
|
|
Meta.State ×
|
|
|
|
|
Elab.Term.State ×
|
|
|
|
|
Elab.Tactic.State ×
|
|
|
|
|
|
|
|
|
|
MVarId ×
|
|
|
|
|
Option MVarId ×
|
|
|
|
|
Option (MVarId × MVarId × List MVarId) ×
|
|
|
|
|
Option (MVarId × Expr)
|
|
|
|
|
) path
|
|
|
|
|
let goalState := {
|
|
|
|
|
savedState := {
|
|
|
|
|
term := {
|
|
|
|
|
meta := {
|
|
|
|
|
core := {
|
|
|
|
|
compactCore with
|
|
|
|
|
passedHeartbeats := 0,
|
|
|
|
|
env,
|
|
|
|
|
},
|
|
|
|
|
meta,
|
|
|
|
|
},
|
|
|
|
|
«elab»,
|
|
|
|
|
},
|
|
|
|
|
tactic,
|
|
|
|
|
},
|
|
|
|
|
root,
|
|
|
|
|
parentMVar?,
|
|
|
|
|
convMVar?,
|
|
|
|
|
calcPrevRhs?,
|
|
|
|
|
}
|
|
|
|
|
return (goalState, region)
|
|
|
|
|
|
2024-11-13 19:50:31 -08:00
|
|
|
|
end Pantograph
|