From 4ab23f9d57297e34272e423b34ff91db0a1053c0 Mon Sep 17 00:00:00 2001 From: rex <1073853456@qq.com> Date: Fri, 11 Apr 2025 04:05:17 +0800 Subject: [PATCH 01/10] add gc option --- REPL/JSON.lean | 9 +++++++-- REPL/Main.lean | 6 +++++- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/REPL/JSON.lean b/REPL/JSON.lean index 24db8402..2b765c0b 100644 --- a/REPL/JSON.lean +++ b/REPL/JSON.lean @@ -27,6 +27,7 @@ If `env = some n`, builds on the existing environment `n`. structure Command extends CommandOptions where env : Option Nat cmd : String + gc : Option Bool := false deriving ToJson, FromJson /-- Process a Lean file in a fresh environment. -/ @@ -121,7 +122,7 @@ A response to a Lean command. `env` can be used in later calls, to build on the stored environment. -/ structure CommandResponse where - env : Nat + env : Option Nat := none messages : List Message := [] sorries : List Sorry := [] tactics : List Tactic := [] @@ -132,9 +133,13 @@ def Json.nonemptyList [ToJson α] (k : String) : List α → List (String × Jso | [] => [] | l => [⟨k, toJson l⟩] +def Json.optField [ToJson α] (k : String) : Option α → List (String × Json) + | none => [] + | some v => [(k, toJson v)] + instance : ToJson CommandResponse where toJson r := Json.mkObj <| .flatten [ - [("env", r.env)], + Json.optField "env" r.env, Json.nonemptyList "messages" r.messages, Json.nonemptyList "sorries" r.sorries, Json.nonemptyList "tactics" r.tactics, diff --git a/REPL/Main.lean b/REPL/Main.lean index ec8bf891..556cc44d 100644 --- a/REPL/Main.lean +++ b/REPL/Main.lean @@ -272,7 +272,11 @@ def runCommand (s : Command) : M IO (CommandResponse ⊕ Error) := do fileMap := default, snap? := none, cancelTk? := none } } - let env ← recordCommandSnapshot cmdSnapshot + let env ← match s.gc with + | some true => pure none + | _ => do + let id ← recordCommandSnapshot cmdSnapshot + pure (some id) let jsonTrees := match s.infotree with | some "full" => trees | some "tactics" => trees.flatMap InfoTree.retainTacticInfo From 8e88e865c0dcc192664616f8ce82f5a84f2a4649 Mon Sep 17 00:00:00 2001 From: rex <1073853456@qq.com> Date: Fri, 11 Apr 2025 04:48:26 +0800 Subject: [PATCH 02/10] add gc option tests --- test/gc.expected.out | 17 ++++++++++++++ test/gc.in | 7 ++++++ test/gc_tactic.expected.out | 44 +++++++++++++++++++++++++++++++++++++ test/gc_tactic.in | 9 ++++++++ 4 files changed, 77 insertions(+) create mode 100644 test/gc.expected.out create mode 100644 test/gc.in create mode 100644 test/gc_tactic.expected.out create mode 100644 test/gc_tactic.in diff --git a/test/gc.expected.out b/test/gc.expected.out new file mode 100644 index 00000000..5778387e --- /dev/null +++ b/test/gc.expected.out @@ -0,0 +1,17 @@ +{"env": 0} + +{"messages": + [{"severity": "info", + "pos": {"line": 1, "column": 0}, + "endPos": {"line": 1, "column": 5}, + "data": "true"}]} + +{"message": "Unknown environment."} + +{"messages": + [{"severity": "info", + "pos": {"line": 1, "column": 0}, + "endPos": {"line": 1, "column": 5}, + "data": "37"}], + "env": 1} + diff --git a/test/gc.in b/test/gc.in new file mode 100644 index 00000000..3d24912e --- /dev/null +++ b/test/gc.in @@ -0,0 +1,7 @@ +{"cmd": "def f := 37"} + +{"cmd": "#eval true", "gc": true} + +{"cmd": "#eval false", "env":1} + +{"cmd": "#eval f", "env":0} diff --git a/test/gc_tactic.expected.out b/test/gc_tactic.expected.out new file mode 100644 index 00000000..d76ff33b --- /dev/null +++ b/test/gc_tactic.expected.out @@ -0,0 +1,44 @@ +{"messages": + [{"severity": "error", + "pos": {"line": 1, "column": 20}, + "endPos": null, + "data": "unexpected end of input; expected '{'"}, + {"severity": "error", + "pos": {"line": 1, "column": 18}, + "endPos": {"line": 1, "column": 20}, + "data": "unsolved goals\n⊢ 2 = 2"}], + "env": 0} + +{"messages": + [{"severity": "info", + "pos": {"line": 1, "column": 0}, + "endPos": {"line": 2, "column": 3}, + "data": "Goals accomplished!"}], + "env": 1} + +{"messages": + [{"severity": "error", + "pos": {"line": 1, "column": 66}, + "endPos": null, + "data": "unexpected end of input; expected '{'"}, + {"severity": "error", + "pos": {"line": 1, "column": 64}, + "endPos": {"line": 1, "column": 66}, + "data": "unsolved goals\nP Q R : Prop\n⊢ (P → Q) → (Q → R) → P → R"}]} + +{"messages": + [{"severity": "error", + "pos": {"line": 1, "column": 64}, + "endPos": {"line": 2, "column": 13}, + "data": "unsolved goals\nP Q R : Prop\nh1 : P → Q\nh2 : Q → R\np : P\n⊢ R"}]} + +{"messages": + [{"severity": "info", + "pos": {"line": 3, "column": 0}, + "endPos": {"line": 3, "column": 6}, + "data": "Try this: exact h2 (h1 p)"}, + {"severity": "info", + "pos": {"line": 1, "column": 0}, + "endPos": {"line": 3, "column": 6}, + "data": "Goals accomplished!"}]} + diff --git a/test/gc_tactic.in b/test/gc_tactic.in new file mode 100644 index 00000000..e0218242 --- /dev/null +++ b/test/gc_tactic.in @@ -0,0 +1,9 @@ +{"cmd": "example : 2=2 := by"} + +{"cmd": "example : 2=2 := by\nrfl"} + +{"cmd": "theorem gc_demo (P Q R : Prop) : (P → Q) → (Q → R) → (P → R) := by", "gc": true} + +{"cmd": "theorem gc_demo (P Q R : Prop) : (P → Q) → (Q → R) → (P → R) := by\nintro h1 h2 p", "gc": true} + +{"cmd": "theorem gc_demo (P Q R : Prop) : (P → Q) → (Q → R) → (P → R) := by\nintro h1 h2 p\napply?", "gc": true} From cf63ddc94f963f705c66618ad32cc9580533dc56 Mon Sep 17 00:00:00 2001 From: rex <1073853456@qq.com> Date: Fri, 11 Apr 2025 13:12:26 +0800 Subject: [PATCH 03/10] update readme --- README.md | 14 ++++++++++++++ REPL/JSON.lean | 2 ++ 2 files changed, 16 insertions(+) diff --git a/README.md b/README.md index d6adc283..8108ccb7 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,19 @@ Commands may be of the form { "cmd" : "example : f = 2 := rfl", "env" : 1 } ``` +```json +{ "cmd" : "example : f = 2 := rfl", "env" : 1, "gc": true } +``` + +The input includes: +* A required `cmd` field containing the Lean command to execute +* An optional `env` field specifying a previous environment ID to build upon +* An optional `gc` field (default: false) to discard the environment after execution +* Optional fields for additional information: + * `allTactics`: when true, includes all tactic steps in the response + * `rootGoals`: when true, includes root goals as sorries + * `infotree`: specifies the level of info tree detail ("full", "tactics", "original", or "substantive") + The `env` field, if present, must contain a number received in the `env` field of a previous response, and causes the command to be run in the existing environment. @@ -33,6 +46,7 @@ You can backtrack simply by using earlier values for `env`. The response includes: * A numeric label for the `Environment` after your command, which you can use as the starting point for subsequent commands. + This will be `none` if `gc` was enabled. * Any messages generated while processing your command. * A list of the `sorry`s in your command, including * their expected type, and diff --git a/REPL/JSON.lean b/REPL/JSON.lean index 2b765c0b..86f81527 100644 --- a/REPL/JSON.lean +++ b/REPL/JSON.lean @@ -23,6 +23,8 @@ structure CommandOptions where /-- Run Lean commands. If `env = none`, starts a new session (in which you can use `import`). If `env = some n`, builds on the existing environment `n`. +Setting `gc = true` will discard the environment after execution, useful for memory management. +When `gc = true`, the response's `env` field will be `none`. -/ structure Command extends CommandOptions where env : Option Nat From bac41b9d7129886db4729798ca1432d6c3f1f55c Mon Sep 17 00:00:00 2001 From: rex <1073853456@qq.com> Date: Mon, 14 Apr 2025 18:37:34 +0800 Subject: [PATCH 04/10] @ohyeat: replace loop by tail recursion --- REPL/Main.lean | 39 ++++++++++++++++++++++----------------- 1 file changed, 22 insertions(+), 17 deletions(-) diff --git a/REPL/Main.lean b/REPL/Main.lean index b63724cd..f383e194 100644 --- a/REPL/Main.lean +++ b/REPL/Main.lean @@ -422,23 +422,28 @@ def printFlush [ToString α] (s : α) : IO Unit := do out.flush -- Flush the output /-- Read-eval-print loop for Lean. -/ -unsafe def repl : IO Unit := - StateT.run' loop {} -where loop : M IO Unit := do - let query ← getLines - if query = "" then - return () - if query.startsWith "#" || query.startsWith "--" then loop else - IO.println <| toString <| ← match ← parse query with - | .command r => return toJson (← runCommand r) - | .file r => return toJson (← processFile r) - | .proofStep r => return toJson (← runProofStep r) - | .pickleEnvironment r => return toJson (← pickleCommandSnapshot r) - | .unpickleEnvironment r => return toJson (← unpickleCommandSnapshot r) - | .pickleProofSnapshot r => return toJson (← pickleProofSnapshot r) - | .unpickleProofSnapshot r => return toJson (← unpickleProofSnapshot r) - printFlush "\n" -- easier to parse the output if there are blank lines - loop +unsafe def repl : IO Unit := do + let rec loop (s : State) : IO Unit := do + let query ← getLines + if query = "" then + return () + else if query.startsWith "#" || query.startsWith "--" then + loop s + else + let (result, s') ← StateT.run (do + match ← parse query with + | .command r => pure <| toJson (← runCommand r) + | .file r => pure <| toJson (← processFile r) + | .proofStep r => pure <| toJson (← runProofStep r) + | .pickleEnvironment r => pure <| toJson (← pickleCommandSnapshot r) + | .unpickleEnvironment r => pure <| toJson (← unpickleCommandSnapshot r) + | .pickleProofSnapshot r => pure <| toJson (← pickleProofSnapshot r) + | .unpickleProofSnapshot r => pure <| toJson (← unpickleProofSnapshot r) + ) s + IO.println (toString result) + printFlush "\n" -- easier to parse the output if there are blank lines + loop s' + loop {} /-- Main executable function, run as `lake exe repl`. -/ unsafe def main (_ : List String) : IO Unit := do From f867ab25215e776d93ffd638c38789f948915968 Mon Sep 17 00:00:00 2001 From: rex <1073853456@qq.com> Date: Wed, 16 Apr 2025 01:07:18 +0800 Subject: [PATCH 05/10] rename `gc` to `discard` --- README.md | 6 +-- REPL/JSON.lean | 6 +-- REPL/Main.lean | 2 +- test/Mathlib/test/discardCmd.expected.out | 30 ++++++++++++++ test/Mathlib/test/discardCmd.in | 9 ++++ ...c.expected.out => discardCmd.expected.out} | 0 test/{gc.in => discardCmd.in} | 2 +- ....expected.out => discardCmd2.expected.out} | 0 test/{gc_tactic.in => discardCmd2.in} | 6 +-- test/discardCmd_proof.expected.out | 41 +++++++++++++++++++ test/discardCmd_proof.in | 11 +++++ 11 files changed, 102 insertions(+), 11 deletions(-) create mode 100644 test/Mathlib/test/discardCmd.expected.out create mode 100644 test/Mathlib/test/discardCmd.in rename test/{gc.expected.out => discardCmd.expected.out} (100%) rename test/{gc.in => discardCmd.in} (68%) rename test/{gc_tactic.expected.out => discardCmd2.expected.out} (100%) rename test/{gc_tactic.in => discardCmd2.in} (62%) create mode 100644 test/discardCmd_proof.expected.out create mode 100644 test/discardCmd_proof.in diff --git a/README.md b/README.md index 8108ccb7..3666fefe 100644 --- a/README.md +++ b/README.md @@ -21,13 +21,13 @@ Commands may be of the form ``` ```json -{ "cmd" : "example : f = 2 := rfl", "env" : 1, "gc": true } +{ "cmd" : "example : f = 2 := rfl", "env" : 1, "discard": true } ``` The input includes: * A required `cmd` field containing the Lean command to execute * An optional `env` field specifying a previous environment ID to build upon -* An optional `gc` field (default: false) to discard the environment after execution +* An optional `discard` field (default: false) to discard the environment after execution * Optional fields for additional information: * `allTactics`: when true, includes all tactic steps in the response * `rootGoals`: when true, includes root goals as sorries @@ -46,7 +46,7 @@ You can backtrack simply by using earlier values for `env`. The response includes: * A numeric label for the `Environment` after your command, which you can use as the starting point for subsequent commands. - This will be `none` if `gc` was enabled. + This will be `none` if `discard` was enabled. * Any messages generated while processing your command. * A list of the `sorry`s in your command, including * their expected type, and diff --git a/REPL/JSON.lean b/REPL/JSON.lean index 86f81527..c5d4781f 100644 --- a/REPL/JSON.lean +++ b/REPL/JSON.lean @@ -23,13 +23,13 @@ structure CommandOptions where /-- Run Lean commands. If `env = none`, starts a new session (in which you can use `import`). If `env = some n`, builds on the existing environment `n`. -Setting `gc = true` will discard the environment after execution, useful for memory management. -When `gc = true`, the response's `env` field will be `none`. +Setting `discard = true` will discard the environment after execution, useful for memory management. +When `discard = true`, the response's `env` field will be `none`. -/ structure Command extends CommandOptions where env : Option Nat cmd : String - gc : Option Bool := false + discard : Option Bool := false deriving ToJson, FromJson /-- Process a Lean file in a fresh environment. -/ diff --git a/REPL/Main.lean b/REPL/Main.lean index f383e194..529e80ad 100644 --- a/REPL/Main.lean +++ b/REPL/Main.lean @@ -322,7 +322,7 @@ def runCommand (s : Command) : M IO (CommandResponse ⊕ Error) := do fileMap := default, snap? := none, cancelTk? := none } } - let env ← match s.gc with + let env ← match s.discard with | some true => pure none | _ => do let id ← recordCommandSnapshot cmdSnapshot diff --git a/test/Mathlib/test/discardCmd.expected.out b/test/Mathlib/test/discardCmd.expected.out new file mode 100644 index 00000000..6182be78 --- /dev/null +++ b/test/Mathlib/test/discardCmd.expected.out @@ -0,0 +1,30 @@ +{"env": 0} + +{"sorries": + [{"proofState": 0, + "pos": {"line": 1, "column": 93}, + "goal": "⊢ (2000 + 2001 + 2002 + 2003 + 2004 + 2005 + 2006) % 7 = 0", + "endPos": {"line": 1, "column": 98}}], + "messages": + [{"severity": "warning", + "pos": {"line": 1, "column": 8}, + "endPos": {"line": 1, "column": 30}, + "data": "declaration uses 'sorry'"}], + "env": 1} + +{"proofStatus": "Completed", "proofState": 1, "goals": []} + +{"sorries": + [{"proofState": 2, + "pos": {"line": 1, "column": 93}, + "goal": "⊢ (2000 + 2001 + 2002 + 2003 + 2004 + 2005 + 2006) % 7 = 0", + "endPos": {"line": 1, "column": 98}}], + "messages": + [{"severity": "warning", + "pos": {"line": 1, "column": 8}, + "endPos": {"line": 1, "column": 30}, + "data": "declaration uses 'sorry'"}], + "env": 2} + +{"proofStatus": "Completed", "proofState": 3, "goals": []} + diff --git a/test/Mathlib/test/discardCmd.in b/test/Mathlib/test/discardCmd.in new file mode 100644 index 00000000..ae2069e6 --- /dev/null +++ b/test/Mathlib/test/discardCmd.in @@ -0,0 +1,9 @@ +{"cmd": "import Mathlib"} + +{"cmd": "theorem mathd_numbertheory_345 : (2000 + 2001 + 2002 + 2003 + 2004 + 2005 + 2006) % 7 = 0 := sorry", "env":0, "discard": true} + +{"tactic": "norm_num", "proofState": 0} + +{"cmd": "theorem mathd_numbertheory_345 : (2000 + 2001 + 2002 + 2003 + 2004 + 2005 + 2006) % 7 = 0 := sorry", "env":0} + +{"tactic": "norm_num", "proofState": 2} diff --git a/test/gc.expected.out b/test/discardCmd.expected.out similarity index 100% rename from test/gc.expected.out rename to test/discardCmd.expected.out diff --git a/test/gc.in b/test/discardCmd.in similarity index 68% rename from test/gc.in rename to test/discardCmd.in index 3d24912e..bee0cfbf 100644 --- a/test/gc.in +++ b/test/discardCmd.in @@ -1,6 +1,6 @@ {"cmd": "def f := 37"} -{"cmd": "#eval true", "gc": true} +{"cmd": "#eval true", "discard": true} {"cmd": "#eval false", "env":1} diff --git a/test/gc_tactic.expected.out b/test/discardCmd2.expected.out similarity index 100% rename from test/gc_tactic.expected.out rename to test/discardCmd2.expected.out diff --git a/test/gc_tactic.in b/test/discardCmd2.in similarity index 62% rename from test/gc_tactic.in rename to test/discardCmd2.in index e0218242..ae7b296d 100644 --- a/test/gc_tactic.in +++ b/test/discardCmd2.in @@ -2,8 +2,8 @@ {"cmd": "example : 2=2 := by\nrfl"} -{"cmd": "theorem gc_demo (P Q R : Prop) : (P → Q) → (Q → R) → (P → R) := by", "gc": true} +{"cmd": "theorem gc_demo (P Q R : Prop) : (P → Q) → (Q → R) → (P → R) := by", "discard": true} -{"cmd": "theorem gc_demo (P Q R : Prop) : (P → Q) → (Q → R) → (P → R) := by\nintro h1 h2 p", "gc": true} +{"cmd": "theorem gc_demo (P Q R : Prop) : (P → Q) → (Q → R) → (P → R) := by\nintro h1 h2 p", "discard": true} -{"cmd": "theorem gc_demo (P Q R : Prop) : (P → Q) → (Q → R) → (P → R) := by\nintro h1 h2 p\napply?", "gc": true} +{"cmd": "theorem gc_demo (P Q R : Prop) : (P → Q) → (Q → R) → (P → R) := by\nintro h1 h2 p\napply?", "discard": true} diff --git a/test/discardCmd_proof.expected.out b/test/discardCmd_proof.expected.out new file mode 100644 index 00000000..2e5fa6d7 --- /dev/null +++ b/test/discardCmd_proof.expected.out @@ -0,0 +1,41 @@ +{"sorries": + [{"proofState": 0, + "pos": {"line": 1, "column": 20}, + "goal": "⊢ 1 = 1", + "endPos": {"line": 1, "column": 25}}], + "messages": + [{"severity": "warning", + "pos": {"line": 1, "column": 0}, + "endPos": {"line": 1, "column": 7}, + "data": "declaration uses 'sorry'"}]} + +{"sorries": + [{"proofState": 1, + "pos": {"line": 1, "column": 20}, + "goal": "⊢ 1 = 1", + "endPos": {"line": 1, "column": 25}}], + "messages": + [{"severity": "warning", + "pos": {"line": 1, "column": 0}, + "endPos": {"line": 1, "column": 7}, + "data": "declaration uses 'sorry'"}], + "env": 0} + +{"sorries": + [{"proofState": 2, + "pos": {"line": 1, "column": 20}, + "goal": "⊢ 1 = 1", + "endPos": {"line": 1, "column": 25}}], + "messages": + [{"severity": "warning", + "pos": {"line": 1, "column": 0}, + "endPos": {"line": 1, "column": 7}, + "data": "declaration uses 'sorry'"}], + "env": 1} + +{"proofStatus": "Completed", "proofState": 3, "goals": []} + +{"proofStatus": "Completed", "proofState": 4, "goals": []} + +{"proofStatus": "Completed", "proofState": 5, "goals": []} + diff --git a/test/discardCmd_proof.in b/test/discardCmd_proof.in new file mode 100644 index 00000000..cd8c8d99 --- /dev/null +++ b/test/discardCmd_proof.in @@ -0,0 +1,11 @@ +{"cmd": "example : 1=1 := by sorry", "discard": true} + +{"cmd": "example : 1=1 := by sorry", "discard": false} + +{"cmd": "example : 1=1 := by sorry"} + +{"tactic": "rfl", "proofState": 0} + +{"tactic": "rfl", "proofState": 1} + +{"tactic": "rfl", "proofState": 2} From 91abba5881793c16c756ff8e1a5b4fc57a586b3e Mon Sep 17 00:00:00 2001 From: rex <1073853456@qq.com> Date: Wed, 16 Apr 2025 01:43:07 +0800 Subject: [PATCH 06/10] rename discard to record --- README.md | 6 +++--- REPL/JSON.lean | 6 +++--- REPL/Main.lean | 7 ++++--- .../{discardCmd.expected.out => record_cmd.expected.out} | 5 ++--- test/Mathlib/test/{discardCmd.in => record_cmd.in} | 2 +- test/{discardCmd.expected.out => record_cmd.expected.out} | 0 test/{discardCmd.in => record_cmd.in} | 2 +- .../{discardCmd2.expected.out => record_cmd2.expected.out} | 0 test/{discardCmd2.in => record_cmd2.in} | 6 +++--- ...md_proof.expected.out => record_cmd_state.expected.out} | 0 test/{discardCmd_proof.in => record_cmd_state.in} | 4 ++-- 11 files changed, 19 insertions(+), 19 deletions(-) rename test/Mathlib/test/{discardCmd.expected.out => record_cmd.expected.out} (93%) rename test/Mathlib/test/{discardCmd.in => record_cmd.in} (80%) rename test/{discardCmd.expected.out => record_cmd.expected.out} (100%) rename test/{discardCmd.in => record_cmd.in} (68%) rename test/{discardCmd2.expected.out => record_cmd2.expected.out} (100%) rename test/{discardCmd2.in => record_cmd2.in} (62%) rename test/{discardCmd_proof.expected.out => record_cmd_state.expected.out} (100%) rename test/{discardCmd_proof.in => record_cmd_state.in} (57%) diff --git a/README.md b/README.md index 3666fefe..e5798820 100644 --- a/README.md +++ b/README.md @@ -21,13 +21,13 @@ Commands may be of the form ``` ```json -{ "cmd" : "example : f = 2 := rfl", "env" : 1, "discard": true } +{ "cmd" : "example : f = 2 := rfl", "env" : 1, "record": false } ``` The input includes: * A required `cmd` field containing the Lean command to execute * An optional `env` field specifying a previous environment ID to build upon -* An optional `discard` field (default: false) to discard the environment after execution +* An optional `record` field (default: true) to record the environment after execution * Optional fields for additional information: * `allTactics`: when true, includes all tactic steps in the response * `rootGoals`: when true, includes root goals as sorries @@ -46,7 +46,7 @@ You can backtrack simply by using earlier values for `env`. The response includes: * A numeric label for the `Environment` after your command, which you can use as the starting point for subsequent commands. - This will be `none` if `discard` was enabled. + This will be `none` if `record` was set to false. * Any messages generated while processing your command. * A list of the `sorry`s in your command, including * their expected type, and diff --git a/REPL/JSON.lean b/REPL/JSON.lean index c5d4781f..b7b3571f 100644 --- a/REPL/JSON.lean +++ b/REPL/JSON.lean @@ -23,13 +23,13 @@ structure CommandOptions where /-- Run Lean commands. If `env = none`, starts a new session (in which you can use `import`). If `env = some n`, builds on the existing environment `n`. -Setting `discard = true` will discard the environment after execution, useful for memory management. -When `discard = true`, the response's `env` field will be `none`. +Setting `record = false` will discard the environment after execution, useful for memory management. +When `record = false`, the response's `env` field will be `none`. -/ structure Command extends CommandOptions where env : Option Nat cmd : String - discard : Option Bool := false + record : Option Bool := true deriving ToJson, FromJson /-- Process a Lean file in a fresh environment. -/ diff --git a/REPL/Main.lean b/REPL/Main.lean index 529e80ad..d627e80c 100644 --- a/REPL/Main.lean +++ b/REPL/Main.lean @@ -322,11 +322,12 @@ def runCommand (s : Command) : M IO (CommandResponse ⊕ Error) := do fileMap := default, snap? := none, cancelTk? := none } } - let env ← match s.discard with - | some true => pure none - | _ => do + let env ← match s.record with + | some false => do pure none + | _ => let id ← recordCommandSnapshot cmdSnapshot pure (some id) + let jsonTrees := match s.infotree with | some "full" => trees | some "tactics" => trees.flatMap InfoTree.retainTacticInfo diff --git a/test/Mathlib/test/discardCmd.expected.out b/test/Mathlib/test/record_cmd.expected.out similarity index 93% rename from test/Mathlib/test/discardCmd.expected.out rename to test/Mathlib/test/record_cmd.expected.out index 6182be78..7f30f1ce 100644 --- a/test/Mathlib/test/discardCmd.expected.out +++ b/test/Mathlib/test/record_cmd.expected.out @@ -9,8 +9,7 @@ [{"severity": "warning", "pos": {"line": 1, "column": 8}, "endPos": {"line": 1, "column": 30}, - "data": "declaration uses 'sorry'"}], - "env": 1} + "data": "declaration uses 'sorry'"}]} {"proofStatus": "Completed", "proofState": 1, "goals": []} @@ -24,7 +23,7 @@ "pos": {"line": 1, "column": 8}, "endPos": {"line": 1, "column": 30}, "data": "declaration uses 'sorry'"}], - "env": 2} + "env": 1} {"proofStatus": "Completed", "proofState": 3, "goals": []} diff --git a/test/Mathlib/test/discardCmd.in b/test/Mathlib/test/record_cmd.in similarity index 80% rename from test/Mathlib/test/discardCmd.in rename to test/Mathlib/test/record_cmd.in index ae2069e6..22dcb8a4 100644 --- a/test/Mathlib/test/discardCmd.in +++ b/test/Mathlib/test/record_cmd.in @@ -1,6 +1,6 @@ {"cmd": "import Mathlib"} -{"cmd": "theorem mathd_numbertheory_345 : (2000 + 2001 + 2002 + 2003 + 2004 + 2005 + 2006) % 7 = 0 := sorry", "env":0, "discard": true} +{"cmd": "theorem mathd_numbertheory_345 : (2000 + 2001 + 2002 + 2003 + 2004 + 2005 + 2006) % 7 = 0 := sorry", "env":0, "record": false} {"tactic": "norm_num", "proofState": 0} diff --git a/test/discardCmd.expected.out b/test/record_cmd.expected.out similarity index 100% rename from test/discardCmd.expected.out rename to test/record_cmd.expected.out diff --git a/test/discardCmd.in b/test/record_cmd.in similarity index 68% rename from test/discardCmd.in rename to test/record_cmd.in index bee0cfbf..8522b4c7 100644 --- a/test/discardCmd.in +++ b/test/record_cmd.in @@ -1,6 +1,6 @@ {"cmd": "def f := 37"} -{"cmd": "#eval true", "discard": true} +{"cmd": "#eval true", "record": false} {"cmd": "#eval false", "env":1} diff --git a/test/discardCmd2.expected.out b/test/record_cmd2.expected.out similarity index 100% rename from test/discardCmd2.expected.out rename to test/record_cmd2.expected.out diff --git a/test/discardCmd2.in b/test/record_cmd2.in similarity index 62% rename from test/discardCmd2.in rename to test/record_cmd2.in index ae7b296d..c71c23fb 100644 --- a/test/discardCmd2.in +++ b/test/record_cmd2.in @@ -2,8 +2,8 @@ {"cmd": "example : 2=2 := by\nrfl"} -{"cmd": "theorem gc_demo (P Q R : Prop) : (P → Q) → (Q → R) → (P → R) := by", "discard": true} +{"cmd": "theorem gc_demo (P Q R : Prop) : (P → Q) → (Q → R) → (P → R) := by", "record": false} -{"cmd": "theorem gc_demo (P Q R : Prop) : (P → Q) → (Q → R) → (P → R) := by\nintro h1 h2 p", "discard": true} +{"cmd": "theorem gc_demo (P Q R : Prop) : (P → Q) → (Q → R) → (P → R) := by\nintro h1 h2 p", "record": false} -{"cmd": "theorem gc_demo (P Q R : Prop) : (P → Q) → (Q → R) → (P → R) := by\nintro h1 h2 p\napply?", "discard": true} +{"cmd": "theorem gc_demo (P Q R : Prop) : (P → Q) → (Q → R) → (P → R) := by\nintro h1 h2 p\napply?", "record": false} diff --git a/test/discardCmd_proof.expected.out b/test/record_cmd_state.expected.out similarity index 100% rename from test/discardCmd_proof.expected.out rename to test/record_cmd_state.expected.out diff --git a/test/discardCmd_proof.in b/test/record_cmd_state.in similarity index 57% rename from test/discardCmd_proof.in rename to test/record_cmd_state.in index cd8c8d99..6305934a 100644 --- a/test/discardCmd_proof.in +++ b/test/record_cmd_state.in @@ -1,6 +1,6 @@ -{"cmd": "example : 1=1 := by sorry", "discard": true} +{"cmd": "example : 1=1 := by sorry", "record": false} -{"cmd": "example : 1=1 := by sorry", "discard": false} +{"cmd": "example : 1=1 := by sorry", "record": true} {"cmd": "example : 1=1 := by sorry"} From edc50794fd2f14c3fd4a7a4359657b7ba0f560d6 Mon Sep 17 00:00:00 2001 From: rex <1073853456@qq.com> Date: Wed, 16 Apr 2025 02:33:15 +0800 Subject: [PATCH 07/10] record for proof states --- REPL/JSON.lean | 5 +++-- REPL/Main.lean | 10 ++++++---- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/REPL/JSON.lean b/REPL/JSON.lean index b7b3571f..f3ef88bd 100644 --- a/REPL/JSON.lean +++ b/REPL/JSON.lean @@ -43,6 +43,7 @@ Run a tactic in a proof state. structure ProofStep where proofState : Nat tactic : String + record: Option Bool := true deriving ToJson, FromJson /-- Line and column information for error messages and sorries. -/ @@ -153,7 +154,7 @@ A response to a Lean tactic. `proofState` can be used in later calls, to run further tactics. -/ structure ProofStepResponse where - proofState : Nat + proofState : Option Nat goals : List String messages : List Message := [] sorries : List Sorry := [] @@ -163,7 +164,7 @@ deriving ToJson, FromJson instance : ToJson ProofStepResponse where toJson r := Json.mkObj <| .flatten [ - [("proofState", r.proofState)], + Json.optField "proofState" r.proofState, [("goals", toJson r.goals)], Json.nonemptyList "messages" r.messages, Json.nonemptyList "sorries" r.sorries, diff --git a/REPL/Main.lean b/REPL/Main.lean index d627e80c..87077a15 100644 --- a/REPL/Main.lean +++ b/REPL/Main.lean @@ -230,8 +230,8 @@ def getProofStatus (proofState : ProofSnapshot) : M m String := do | _ => return "Incomplete: open goals remain" /-- Record a `ProofSnapshot` and generate a JSON response for it. -/ -def createProofStepReponse (proofState : ProofSnapshot) (old? : Option ProofSnapshot := none) : - M m ProofStepResponse := do +def createProofStepReponse (proofState : ProofSnapshot) (old? : Option ProofSnapshot := none) + (record : Option Bool := true) : M m ProofStepResponse := do let messages := proofState.newMessages old? let messages ← messages.mapM fun m => Message.of m let traces ← proofState.newTraces old? @@ -245,7 +245,9 @@ def createProofStepReponse (proofState : ProofSnapshot) (old? : Option ProofSnap -- For debugging purposes, sometimes we print out the trees here: -- trees.forM fun t => do IO.println (← t.format) let sorries ← sorries trees none (some proofState.rootGoals) - let id ← recordProofSnapshot proofState + let id ← match record with + | some false => pure none + | _ => some <$> recordProofSnapshot proofState return { proofState := id goals := (← proofState.ppGoals).map fun s => s!"{s}" @@ -362,7 +364,7 @@ def runProofStep (s : ProofStep) : M IO (ProofStepResponse ⊕ Error) := do | some proofState => try let proofState' ← proofState.runString s.tactic - return .inl (← createProofStepReponse proofState' proofState) + return .inl (← createProofStepReponse proofState' proofState s.record) catch ex => return .inr ⟨"Lean error:\n" ++ ex.toString⟩ From b1cb4e73fdcc9f2064f1bc79d2d424c78c742ca9 Mon Sep 17 00:00:00 2001 From: rex <1073853456@qq.com> Date: Sun, 4 May 2025 06:51:21 +0800 Subject: [PATCH 08/10] rename tests --- .../{record_cmd_state.expected.out => record_tactic.expected.out} | 0 test/{record_cmd_state.in => record_tactic.in} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename test/{record_cmd_state.expected.out => record_tactic.expected.out} (100%) rename test/{record_cmd_state.in => record_tactic.in} (100%) diff --git a/test/record_cmd_state.expected.out b/test/record_tactic.expected.out similarity index 100% rename from test/record_cmd_state.expected.out rename to test/record_tactic.expected.out diff --git a/test/record_cmd_state.in b/test/record_tactic.in similarity index 100% rename from test/record_cmd_state.in rename to test/record_tactic.in From d374f1b8dd36358c22dafa81f2215b418ebe71a6 Mon Sep 17 00:00:00 2001 From: rex <1073853456@qq.com> Date: Fri, 4 Jul 2025 16:13:22 +0800 Subject: [PATCH 09/10] update test scripts --- test.sh | 25 +++++++++++++++++++++++-- test/Mathlib/test.sh | 21 +++++++++++++++++++-- 2 files changed, 42 insertions(+), 4 deletions(-) diff --git a/test.sh b/test.sh index be8e1b3f..0af7e5e3 100755 --- a/test.sh +++ b/test.sh @@ -6,6 +6,10 @@ EXPECTED_DIR="test" lake build +# Initialize variables to track failures +failed_tests=() +failure_count=0 + # ignore locale to ensure test `bla` runs before `bla2` export LC_COLLATE=C @@ -36,11 +40,28 @@ for infile in $IN_DIR/*.in; do echo "$base: FAILED" # Rename the temporary file instead of removing it mv "$tmpfile" "${expectedfile/.expected.out/.produced.out}" - exit 1 + failed_tests+=("$base") + ((failure_count++)) fi - done +# Print summary of failures +if [ ${#failed_tests[@]} -ne 0 ]; then + echo -e "\n=== Test Summary ===" + echo "Failed tests:" + for test in "${failed_tests[@]}"; do + echo "✗ $test" + done + echo -e "\nTotal: $failure_count failed" + echo "==================" +fi + # Run the Mathlib tests cp lean-toolchain test/Mathlib/ cd test/Mathlib/ && ./test.sh +mathlib_exit_code=$? + +# Exit with error if any test failed or if Mathlib tests failed +if [ $failure_count -gt 0 ] || [ $mathlib_exit_code -ne 0 ]; then + exit 1 +fi diff --git a/test/Mathlib/test.sh b/test/Mathlib/test.sh index 0f9f89fe..b1f220df 100755 --- a/test/Mathlib/test.sh +++ b/test/Mathlib/test.sh @@ -4,6 +4,10 @@ IN_DIR="test" EXPECTED_DIR="test" +# Initialize variables to track failures +failed_tests=() +failure_count=0 + lake exe cache get > /dev/null lake build Mathlib @@ -34,8 +38,21 @@ for infile in $IN_DIR/*.in; do echo "$base: FAILED" # Rename the temporary file instead of removing it mv "$tmpfile" "${expectedfile/.expected.out/.produced.out}" - exit 1 + failed_tests+=("$base") + ((failure_count++)) fi - done +# Print summary of failures +if [ ${#failed_tests[@]} -ne 0 ]; then + echo -e "\n=== Mathlib Test Summary ===" + echo "Failed tests:" + for test in "${failed_tests[@]}"; do + echo "✗ $test" + done + echo -e "\nTotal: $failure_count failed" + echo "========================" + exit 1 +fi + +exit 0 From 3d719445fc842990da20f038d87a4839eac07dcd Mon Sep 17 00:00:00 2001 From: rex <1073853456@qq.com> Date: Thu, 24 Jul 2025 04:29:19 +0800 Subject: [PATCH 10/10] fix error test --- test/record_cmd2.expected.out | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/test/record_cmd2.expected.out b/test/record_cmd2.expected.out index d76ff33b..f581d6cf 100644 --- a/test/record_cmd2.expected.out +++ b/test/record_cmd2.expected.out @@ -9,12 +9,7 @@ "data": "unsolved goals\n⊢ 2 = 2"}], "env": 0} -{"messages": - [{"severity": "info", - "pos": {"line": 1, "column": 0}, - "endPos": {"line": 2, "column": 3}, - "data": "Goals accomplished!"}], - "env": 1} +{"env": 1} {"messages": [{"severity": "error", @@ -36,9 +31,5 @@ [{"severity": "info", "pos": {"line": 3, "column": 0}, "endPos": {"line": 3, "column": 6}, - "data": "Try this: exact h2 (h1 p)"}, - {"severity": "info", - "pos": {"line": 1, "column": 0}, - "endPos": {"line": 3, "column": 6}, - "data": "Goals accomplished!"}]} + "data": "Try this: exact h2 (h1 p)"}]}