-
Notifications
You must be signed in to change notification settings - Fork 16
Expand file tree
/
Copy pathExtractSimple.lean
More file actions
163 lines (131 loc) · 5.4 KB
/
Copy pathExtractSimple.lean
File metadata and controls
163 lines (131 loc) · 5.4 KB
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
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
-- A minimal version of LeanDojo's ExtractData.lean for instructional purposes.
-- Please see LeanDojo's ExtractData.lean for a full working script to use in practice.
--
-- Credits: original script is from LeanDojo https://github.com/lean-dojo/LeanDojo/
-- @article{yang2023leandojo,
-- title={{LeanDojo}: Theorem Proving with Retrieval-Augmented Language Models},
-- author={Yang, Kaiyu and Swope, Aidan and Gu, Alex and Chalamala, Rahul and Song,
-- Peiyang and Yu, Shixing and Godil, Saad and Prenger, Ryan and Anandkumar, Anima},
-- journal={arXiv preprint arXiv:2306.15626},
-- year={2023}
-- }
-- This script is essentially a slightly refactored subset of LeanDojo's script.
import Lean
open Lean Elab System
instance : ToJson Substring where
toJson s := toJson s.toString
instance : ToJson String.Pos where
toJson n := toJson n.1
deriving instance ToJson for SourceInfo
deriving instance ToJson for Syntax.Preresolved
deriving instance ToJson for Syntax
structure TacticTrace where
stateBefore: String
stateAfter: String
pos: String.Pos
endPos: String.Pos
deriving ToJson
structure Trace where
commandASTs : Array Syntax
tactics: Array TacticTrace
deriving ToJson
abbrev TraceM := StateT Trace IO
def ppGoals (ctx : ContextInfo) (goals : List MVarId) : IO String :=
if goals.isEmpty then
return "no goals"
else
let fmt := ctx.runMetaM {} (return Std.Format.prefixJoin "\n\n" (← goals.mapM (Meta.ppGoal ·)))
return (← fmt).pretty.trim
private def visitTacticInfo (ctx : ContextInfo) (ti : TacticInfo) (parent : InfoTree) : TraceM Unit := do
match parent with
| .node (Info.ofTacticInfo i) _ =>
match i.stx.getKind with
| `Lean.Parser.Tactic.tacticSeq1Indented | `Lean.Parser.Tactic.tacticSeqBracketed =>
let ctxBefore := { ctx with mctx := ti.mctxBefore }
let ctxAfter := { ctx with mctx := ti.mctxAfter }
let stateBefore ← ppGoals ctxBefore ti.goalsBefore
let stateAfter ← ppGoals ctxAfter ti.goalsAfter
let some posBefore := ti.stx.getPos? true | pure ()
let some posAfter := ti.stx.getTailPos? true | pure ()
match ti.stx with
| .node _ _ _ =>
modifyGet fun trace => ((),
{ trace with tactics := trace.tactics.push {
stateBefore := stateBefore,
stateAfter := stateAfter,
pos := posBefore,
endPos := posAfter } }
)
| _ => pure ()
| _ => pure ()
| _ => pure ()
private def visitInfo (ctx : ContextInfo) (i : Info) (parent : InfoTree) : TraceM Unit := do
match i with
| .ofTacticInfo ti => visitTacticInfo ctx ti parent
| _ => pure ()
private partial def traverseTree (ctx: ContextInfo) (tree : InfoTree) (parent : InfoTree) : TraceM Unit := do
match tree with
| .context ctx' t => traverseTree ctx' t tree
| .node i children =>
visitInfo ctx i parent
for x in children do
traverseTree ctx x tree
| _ => pure ()
private def traverseTopLevelTree (tree : InfoTree) : TraceM Unit := do
match tree with
| .context ctx t => traverseTree ctx t tree
| _ => throw $ IO.userError "Errors in traverseTopLevelTree; aborting"
def traverseForest (trees : Array InfoTree) : TraceM Trace := do
for t in trees do
traverseTopLevelTree t
get
def relativeTo (path parent : FilePath) : Option FilePath :=
let rec componentsRelativeTo (pathComps parentComps : List String) : Option FilePath :=
match pathComps, parentComps with
| _, [] => mkFilePath pathComps
| [], _ => none
| (h₁ :: t₁), (h₂ :: t₂) =>
if h₁ == h₂ then
componentsRelativeTo t₁ t₂
else
none
componentsRelativeTo path.components parent.components
def toAbsolute (path : FilePath) : IO FilePath := do
if path.isAbsolute then
pure path
else
let cwd ← IO.currentDir
pure $ cwd / path
unsafe def processFile (path : FilePath) : IO Unit := do
let input ← IO.FS.readFile path
let opts := Options.empty.setBool `trace.Elab.info true
enableInitializersExecution
let inputCtx := Parser.mkInputContext input path.toString
let (header, parserState, messages) ← Parser.parseHeader inputCtx
let (env, messages) ← processHeader header opts messages inputCtx
if messages.hasErrors then
for msg in messages.toList do
if msg.severity == .error then
println! "ERROR: {← msg.toString}"
throw $ IO.userError "Errors during import; aborting"
let some modName := path.fileStem | throw $ IO.userError s!"Invalid path: {path}"
let env := env.setMainModule modName.toName
let commandState := { Command.mkState env messages opts with infoState.enabled := true }
let s ← IO.processCommands inputCtx parserState commandState
let commands := s.commands.pop -- Remove EOI command.
let trees := s.commandState.infoState.trees.toArray
let trace ← (traverseForest trees).run' ⟨#[header] ++ commands, #[]⟩
let cwd ← IO.currentDir
let some relativePath := relativeTo path cwd | throw $ IO.userError s!"Invalid path: {path}"
println! "Input file: {relativePath}"
let json_path := (
relativePath.withExtension "ast.json"
)
IO.FS.writeFile json_path (toJson trace).pretty
println! "AST: {json_path}"
unsafe def main (args : List String) : IO Unit := do
match args with
| path :: _ =>
processFile (← toAbsolute ⟨path⟩)
| [] =>
println! "Please provide a .lean file (lake env lean --run ExtractData.lean FILENAME.lean)"