Compare commits

..

No commits in common. "ba84456f89646fb147fd9bfcfefd7b76778c3c65" and "3d65f6a69ee097108e11afa9df17893e0d94e6bc" have entirely different histories.

3 changed files with 236 additions and 238 deletions

View File

@ -361,8 +361,8 @@ structure FrontendProcess where
readHeader : Bool := false readHeader : Bool := false
-- Alter the REPL environment after the compilation units. -- Alter the REPL environment after the compilation units.
inheritEnv : Bool := false inheritEnv : Bool := false
-- collect tactic invocations and output to a given file -- collect tactic invocations
invocations?: Option String := .none invocations: Bool := false
-- collect `sorry`s -- collect `sorry`s
sorrys: Bool := false sorrys: Bool := false
-- collect type errors -- collect type errors
@ -383,8 +383,8 @@ structure CompilationUnit where
-- String boundaries of compilation units -- String boundaries of compilation units
boundary: (Nat × Nat) boundary: (Nat × Nat)
messages: Array String := #[] messages: Array String := #[]
-- Number of tactic invocations -- Tactic invocations
nInvocations?: Option Nat := .none invocations?: Option (List InvokedTactic) := .none
goalStateId?: Option Nat := .none goalStateId?: Option Nat := .none
goals?: Option (Array Goal) := .none goals?: Option (Array Goal) := .none
-- Code segments which generated the goals -- Code segments which generated the goals
@ -396,12 +396,6 @@ structure CompilationUnit where
structure FrontendProcessResult where structure FrontendProcessResult where
units: List CompilationUnit units: List CompilationUnit
deriving Lean.ToJson deriving Lean.ToJson
structure FrontendDataUnit where
invocations? : Option (List Protocol.InvokedTactic) := .none
deriving Lean.ToJson
structure FrontendData where
units : List FrontendDataUnit
deriving Lean.ToJson
abbrev FallibleT := ExceptT InteractionError abbrev FallibleT := ExceptT InteractionError

View File

@ -125,7 +125,7 @@ def frontend_process (args: Protocol.FrontendProcess): EMainM Protocol.FrontendP
let frontendM: Elab.Frontend.FrontendM (List CompilationUnit) := let frontendM: Elab.Frontend.FrontendM (List CompilationUnit) :=
Frontend.mapCompilationSteps λ step => do Frontend.mapCompilationSteps λ step => do
let boundary := (step.src.startPos.byteIdx, step.src.stopPos.byteIdx) let boundary := (step.src.startPos.byteIdx, step.src.stopPos.byteIdx)
let invocations: Option (List Protocol.InvokedTactic) ← if args.invocations?.isSome then let invocations: Option (List Protocol.InvokedTactic) ← if args.invocations then
Frontend.collectTacticsFromCompilationStep step Frontend.collectTacticsFromCompilationStep step
else else
pure [] pure []
@ -152,10 +152,6 @@ def frontend_process (args: Protocol.FrontendProcess): EMainM Protocol.FrontendP
if let .some scope := state'.commandState.scopes.head? then if let .some scope := state'.commandState.scopes.head? then
-- modify the scope -- modify the scope
set { ← getMainState with scope } set { ← getMainState with scope }
if let .some fileName := args.invocations? then
let units := li.map λ unit => { invocations? := .some unit.invocations }
let data : Protocol.FrontendData := { units }
IO.FS.writeFile fileName (toJson data |>.compress)
let units ← li.mapM λ step => withEnv step.env do let units ← li.mapM λ step => withEnv step.env do
let newConstants? := if args.newConstants then let newConstants? := if args.newConstants then
.some $ step.newConstants.toArray.map λ name => name.toString .some $ step.newConstants.toArray.map λ name => name.toString
@ -171,11 +167,11 @@ def frontend_process (args: Protocol.FrontendProcess): EMainM Protocol.FrontendP
let stateId ← newGoalState state let stateId ← newGoalState state
let srcBoundaries := srcBoundaries.toArray.map (λ (b, e) => (b.byteIdx, e.byteIdx)) let srcBoundaries := srcBoundaries.toArray.map (λ (b, e) => (b.byteIdx, e.byteIdx))
pure (.some stateId, .some goals, .some srcBoundaries) pure (.some stateId, .some goals, .some srcBoundaries)
let nInvocations? := if args.invocations?.isSome then .some step.invocations.length else .none let invocations? := if args.invocations then .some step.invocations else .none
return { return {
boundary := step.boundary, boundary := step.boundary,
messages := step.messages, messages := step.messages,
nInvocations?, invocations?,
goalStateId?, goalStateId?,
goals?, goals?,
goalSrcBoundaries?, goalSrcBoundaries?,

View File

@ -17,59 +17,53 @@ deriving instance Lean.ToJson for Protocol.GoalStart
deriving instance Lean.ToJson for Protocol.GoalPrint deriving instance Lean.ToJson for Protocol.GoalPrint
deriving instance Lean.ToJson for Protocol.GoalTactic deriving instance Lean.ToJson for Protocol.GoalTactic
deriving instance Lean.ToJson for Protocol.FrontendProcess deriving instance Lean.ToJson for Protocol.FrontendProcess
deriving instance Lean.ToJson for Protocol.FrontendDataUnit
deriving instance Lean.ToJson for Protocol.FrontendData
abbrev TestM α := TestT MainM α
abbrev Test := TestM Unit
def step { α β } [Lean.ToJson α] [Lean.ToJson β] (cmd: String) (payload: α) def step { α β } [Lean.ToJson α] [Lean.ToJson β] (cmd: String) (payload: α)
(expected: β) (name? : Option String := .none) : TestM Unit := do (expected: β) (name? : Option String := .none): MainM LSpec.TestSeq := do
let payload := Lean.toJson payload let payload := Lean.toJson payload
let name := name?.getD s!"{cmd} {payload.compress}" let name := name?.getD s!"{cmd} {payload.compress}"
let result ← Repl.execute { cmd, payload } let result ← Repl.execute { cmd, payload }
checkEq name result.compress (Lean.toJson expected).compress return LSpec.test name (result.pretty = (Lean.toJson expected).pretty)
def stepFile { α } [Lean.ToJson α] (name : String) (path : String)
(expected : α) : TestM Unit := do abbrev Test := List (MainM LSpec.TestSeq)
let content ← IO.FS.readFile path
let payload? : Except String Lean.Json := Lean.Json.parse content
match payload? with
| .ok payload =>
let expected := Lean.toJson expected
checkEq name payload.compress expected.compress
| .error e => fail s!"{name} {e}"
def test_expr_echo : Test := def test_expr_echo : Test :=
step "expr.echo" [
({ expr := "λ {α : Sort (u + 1)} => List α", levels? := .some #["u"]}: Protocol.ExprEcho) step "expr.echo"
({ ({ expr := "λ {α : Sort (u + 1)} => List α", levels? := .some #["u"]}: Protocol.ExprEcho)
type := { pp? := .some "{α : Type u} → Type u" }, ({
expr := { pp? := .some "fun {α} => List α" } type := { pp? := .some "{α : Type u} → Type u" },
}: Protocol.ExprEchoResult) expr := { pp? := .some "fun {α} => List α" }
}: Protocol.ExprEchoResult),
]
def test_option_modify : Test := do def test_option_modify : Test :=
let pp? := Option.some "∀ (n : Nat), n + 1 = n.succ" let pp? := Option.some "∀ (n : Nat), n + 1 = n.succ"
let sexp? := Option.some "(:forall n (:c Nat) ((:c Eq) (:c Nat) ((:c HAdd.hAdd) (:c Nat) (:c Nat) (:c Nat) ((:c instHAdd) (:c Nat) (:c instAddNat)) 0 ((:c OfNat.ofNat) (:c Nat) (:lit 1) ((:c instOfNatNat) (:lit 1)))) ((:c Nat.succ) 0)))" let sexp? := Option.some "(:forall n (:c Nat) ((:c Eq) (:c Nat) ((:c HAdd.hAdd) (:c Nat) (:c Nat) (:c Nat) ((:c instHAdd) (:c Nat) (:c instAddNat)) 0 ((:c OfNat.ofNat) (:c Nat) (:lit 1) ((:c instOfNatNat) (:lit 1)))) ((:c Nat.succ) 0)))"
let module? := Option.some "Init.Data.Nat.Basic" let module? := Option.some "Init.Data.Nat.Basic"
let options: Protocol.Options := {} let options: Protocol.Options := {}
step "env.inspect" ({ name := "Nat.add_one" } : Protocol.EnvInspect) [
({ type := { pp? }, module? }: Protocol.EnvInspectResult) step "env.inspect" ({ name := "Nat.add_one" } : Protocol.EnvInspect)
step "options.set" ({ printExprAST? := .some true } : Protocol.OptionsSet) ({ type := { pp? }, module? }: Protocol.EnvInspectResult),
({ }: Protocol.OptionsSetResult) step "options.set" ({ printExprAST? := .some true } : Protocol.OptionsSet)
step "env.inspect" ({ name := "Nat.add_one" } : Protocol.EnvInspect) ({ }: Protocol.OptionsSetResult),
({ type := { pp?, sexp? }, module? }: Protocol.EnvInspectResult) step "env.inspect" ({ name := "Nat.add_one" } : Protocol.EnvInspect)
step "options.print" ({} : Protocol.OptionsPrint) ({ type := { pp?, sexp? }, module? }: Protocol.EnvInspectResult),
({ options with printExprAST := true }: Protocol.Options) step "options.print" ({} : Protocol.OptionsPrint)
({ options with printExprAST := true }: Protocol.Options),
def test_malformed_command : Test := do ]
def test_malformed_command : Test :=
let invalid := "invalid" let invalid := "invalid"
step invalid ({ name := "Nat.add_one" }: Protocol.EnvInspect) [
({ error := "command", desc := s!"Unknown command {invalid}" }: Protocol.InteractionError) step invalid ({ name := "Nat.add_one" }: Protocol.EnvInspect)
(name? := .some "Invalid Command") ({ error := "command", desc := s!"Unknown command {invalid}" }: Protocol.InteractionError)
step "expr.echo" (Lean.Json.mkObj [(invalid, .str "Random garbage data")]) (name? := .some "Invalid Command"),
({ error := "command", desc := s!"Unable to parse json: Pantograph.Protocol.ExprEcho.expr: String expected" }: step "expr.echo" (Lean.Json.mkObj [(invalid, .str "Random garbage data")])
Protocol.InteractionError) (name? := .some "JSON Deserialization") ({ error := "command", desc := s!"Unable to parse json: Pantograph.Protocol.ExprEcho.expr: String expected" }:
def test_tactic : Test := do Protocol.InteractionError)
(name? := .some "JSON Deserialization")
]
def test_tactic : Test :=
let varX := { name := "_uniq.10", userName := "x", type? := .some { pp? := .some "Prop" }} let varX := { name := "_uniq.10", userName := "x", type? := .some { pp? := .some "Prop" }}
let goal1: Protocol.Goal := { let goal1: Protocol.Goal := {
name := "_uniq.11", name := "_uniq.11",
@ -84,39 +78,43 @@ def test_tactic : Test := do
{ name := "_uniq.13", userName := "y", type? := .some { pp? := .some "Prop" }} { name := "_uniq.13", userName := "y", type? := .some { pp? := .some "Prop" }}
], ],
} }
step "goal.start" ({ expr := "∀ (p q: Prop), p q → q p" }: Protocol.GoalStart) [
({ stateId := 0, root := "_uniq.9" }: Protocol.GoalStartResult) step "goal.start" ({ expr := "∀ (p q: Prop), p q → q p" }: Protocol.GoalStart)
step "goal.tactic" ({ stateId := 0, tactic? := .some "intro x" }: Protocol.GoalTactic) ({ stateId := 0, root := "_uniq.9" }: Protocol.GoalStartResult),
({ nextStateId? := .some 1, goals? := #[goal1], }: Protocol.GoalTacticResult) step "goal.tactic" ({ stateId := 0, tactic? := .some "intro x" }: Protocol.GoalTactic)
step "goal.print" ({ stateId := 1, parentExpr? := .some true, rootExpr? := .some true }: Protocol.GoalPrint) ({ nextStateId? := .some 1, goals? := #[goal1], }: Protocol.GoalTacticResult),
({ step "goal.print" ({ stateId := 1, parentExpr? := .some true, rootExpr? := .some true }: Protocol.GoalPrint)
root? := .some { pp? := "fun x => ?m.11"}, ({
parent? := .some { pp? := .some "fun x => ?m.11" }, root? := .some { pp? := "fun x => ?m.11"},
}: Protocol.GoalPrintResult) parent? := .some { pp? := .some "fun x => ?m.11" },
step "goal.tactic" ({ stateId := 1, tactic? := .some "intro y" }: Protocol.GoalTactic) }: Protocol.GoalPrintResult),
({ nextStateId? := .some 2, goals? := #[goal2], }: Protocol.GoalTacticResult) step "goal.tactic" ({ stateId := 1, tactic? := .some "intro y" }: Protocol.GoalTactic)
step "goal.tactic" ({ stateId := 1, tactic? := .some "apply Nat.le_of_succ_le" }: Protocol.GoalTactic) ({ nextStateId? := .some 2, goals? := #[goal2], }: Protocol.GoalTacticResult),
({ messages? := .some #["tactic 'apply' failed, failed to unify\n ∀ {m : Nat}, Nat.succ ?n ≤ m → ?n ≤ m\nwith\n ∀ (q : Prop), x q → q x\nx : Prop\n⊢ ∀ (q : Prop), x q → q x"] }: step "goal.tactic" ({ stateId := 1, tactic? := .some "apply Nat.le_of_succ_le" }: Protocol.GoalTactic)
Protocol.GoalTacticResult) ({ messages? := .some #["tactic 'apply' failed, failed to unify\n ∀ {m : Nat}, Nat.succ ?n ≤ m → ?n ≤ m\nwith\n ∀ (q : Prop), x q → q x\nx : Prop\n⊢ ∀ (q : Prop), x q → q x"] }:
step "goal.tactic" ({ stateId := 0, tactic? := .some "sorry" }: Protocol.GoalTactic) Protocol.GoalTacticResult),
({ nextStateId? := .some 3, goals? := .some #[], hasSorry := true }: Protocol.GoalTacticResult) step "goal.tactic" ({ stateId := 0, tactic? := .some "sorry" }: Protocol.GoalTactic)
({ nextStateId? := .some 3, goals? := .some #[], hasSorry := true }: Protocol.GoalTacticResult),
]
example : (1 : Nat) + (2 * 3) = 1 + (4 - 3) + (6 - 4) + 3 := by example : (1 : Nat) + (2 * 3) = 1 + (4 - 3) + (6 - 4) + 3 := by
simp simp
def test_tactic_timeout : Test := do def test_tactic_timeout : Test :=
step "goal.start" ({ expr := "(1 : Nat) + (2 * 3) = 1 + (4 - 3) + (6 - 4) + 3" }: Protocol.GoalStart) [
({ stateId := 0, root := "_uniq.319" }: Protocol.GoalStartResult) step "goal.start" ({ expr := "(1 : Nat) + (2 * 3) = 1 + (4 - 3) + (6 - 4) + 3" }: Protocol.GoalStart)
-- timeout of 10 milliseconds ({ stateId := 0, root := "_uniq.319" }: Protocol.GoalStartResult),
step "options.set" ({ timeout? := .some 10 } : Protocol.OptionsSet) -- timeout of 10 milliseconds
({ }: Protocol.OptionsSetResult) step "options.set" ({ timeout? := .some 10 } : Protocol.OptionsSet)
step "goal.tactic" ({ stateId := 0, expr? := .some "by\nsleep 1000; simp" }: Protocol.GoalTactic) ({ }: Protocol.OptionsSetResult),
({ error := "internal", desc := "interrupt" }: Protocol.InteractionError) step "goal.tactic" ({ stateId := 0, expr? := .some "by\nsleep 1000; simp" }: Protocol.GoalTactic)
-- ensure graceful recovery ({ error := "internal", desc := "interrupt" }: Protocol.InteractionError),
step "options.set" ({ timeout? := .some 0 } : Protocol.OptionsSet) -- ensure graceful recovery
({ }: Protocol.OptionsSetResult) step "options.set" ({ timeout? := .some 0 } : Protocol.OptionsSet)
step "goal.tactic" ({ stateId := 0, tactic? := .some "simp" }: Protocol.GoalTactic) ({ }: Protocol.OptionsSetResult),
({ nextStateId? := .some 1, goals? := .some #[], }: Protocol.GoalTacticResult) step "goal.tactic" ({ stateId := 0, tactic? := .some "simp" }: Protocol.GoalTactic)
({ nextStateId? := .some 1, goals? := .some #[], }: Protocol.GoalTacticResult),
]
def test_automatic_mode (automatic: Bool): Test := do def test_automatic_mode (automatic: Bool): Test :=
let varsPQ := #[ let varsPQ := #[
{ name := "_uniq.10", userName := "p", type? := .some { pp? := .some "Prop" }}, { name := "_uniq.10", userName := "p", type? := .some { pp? := .some "Prop" }},
{ name := "_uniq.13", userName := "q", type? := .some { pp? := .some "Prop" }} { name := "_uniq.13", userName := "q", type? := .some { pp? := .some "Prop" }}
@ -152,186 +150,196 @@ def test_automatic_mode (automatic: Bool): Test := do
{ name := "_uniq.49", userName := "h✝", type? := .some { pp? := .some "p" }, isInaccessible := true} { name := "_uniq.49", userName := "h✝", type? := .some { pp? := .some "p" }, isInaccessible := true}
], ],
} }
step "options.set" ({automaticMode? := .some automatic}: Protocol.OptionsSet) [
({}: Protocol.OptionsSetResult) step "options.set" ({automaticMode? := .some automatic}: Protocol.OptionsSet)
step "goal.start" ({ expr := "∀ (p q: Prop), p q → q p"} : Protocol.GoalStart) ({}: Protocol.OptionsSetResult),
({ stateId := 0, root := "_uniq.9" }: Protocol.GoalStartResult) step "goal.start" ({ expr := "∀ (p q: Prop), p q → q p"} : Protocol.GoalStart)
step "goal.tactic" ({ stateId := 0, tactic? := .some "intro p q h" }: Protocol.GoalTactic) ({ stateId := 0, root := "_uniq.9" }: Protocol.GoalStartResult),
({ nextStateId? := .some 1, goals? := #[goal1], }: Protocol.GoalTacticResult) step "goal.tactic" ({ stateId := 0, tactic? := .some "intro p q h" }: Protocol.GoalTactic)
step "goal.tactic" ({ stateId := 1, tactic? := .some "cases h" }: Protocol.GoalTactic) ({ nextStateId? := .some 1, goals? := #[goal1], }: Protocol.GoalTacticResult),
({ nextStateId? := .some 2, goals? := #[goal2l, goal2r], }: Protocol.GoalTacticResult) step "goal.tactic" ({ stateId := 1, tactic? := .some "cases h" }: Protocol.GoalTactic)
let goals? := if automatic then #[goal3l, goal2r] else #[goal3l] ({ nextStateId? := .some 2, goals? := #[goal2l, goal2r], }: Protocol.GoalTacticResult),
step "goal.tactic" ({ stateId := 2, tactic? := .some "apply Or.inr" }: Protocol.GoalTactic) let goals? := if automatic then #[goal3l, goal2r] else #[goal3l]
({ nextStateId? := .some 3, goals?, }: Protocol.GoalTacticResult) step "goal.tactic" ({ stateId := 2, tactic? := .some "apply Or.inr" }: Protocol.GoalTactic)
({ nextStateId? := .some 3, goals?, }: Protocol.GoalTacticResult),
]
def test_env_add_inspect : Test := do def test_env_add_inspect : Test :=
let name1 := "Pantograph.mystery" let name1 := "Pantograph.mystery"
let name2 := "Pantograph.mystery2" let name2 := "Pantograph.mystery2"
let name3 := "Pantograph.mystery3" let name3 := "Pantograph.mystery3"
step "env.add" [
({ step "env.add"
name := name1, ({
value := "λ (a b: Prop) => Or a b", name := name1,
isTheorem := false value := "λ (a b: Prop) => Or a b",
}: Protocol.EnvAdd) isTheorem := false
({}: Protocol.EnvAddResult) }: Protocol.EnvAdd)
step "env.inspect" ({name := name1, value? := .some true} : Protocol.EnvInspect) ({}: Protocol.EnvAddResult),
({ step "env.inspect" ({name := name1, value? := .some true} : Protocol.EnvInspect)
value? := .some { pp? := .some "fun a b => a b" }, ({
type := { pp? := .some "Prop → Prop → Prop" }, value? := .some { pp? := .some "fun a b => a b" },
}: Protocol.EnvInspectResult) type := { pp? := .some "Prop → Prop → Prop" },
step "env.add" }:
({ Protocol.EnvInspectResult),
name := name2, step "env.add"
type? := "Nat → Int", ({
value := "λ (a: Nat) => a + 1", name := name2,
isTheorem := false type? := "Nat → Int",
}: Protocol.EnvAdd) value := "λ (a: Nat) => a + 1",
({}: Protocol.EnvAddResult) isTheorem := false
step "env.inspect" ({name := name2, value? := .some true} : Protocol.EnvInspect) }: Protocol.EnvAdd)
({ ({}: Protocol.EnvAddResult),
value? := .some { pp? := .some "fun a => ↑a + 1" }, step "env.inspect" ({name := name2, value? := .some true} : Protocol.EnvInspect)
type := { pp? := .some "Nat → Int" }, ({
}: Protocol.EnvInspectResult) value? := .some { pp? := .some "fun a => ↑a + 1" },
step "env.add" type := { pp? := .some "Nat → Int" },
({ }:
name := name3, Protocol.EnvInspectResult),
levels? := .some #["u"] step "env.add"
type? := "(α : Type u) → α → (α × α)", ({
value := "λ (α : Type u) (x : α) => (x, x)", name := name3,
isTheorem := false levels? := .some #["u"]
}: Protocol.EnvAdd) type? := "(α : Type u) → α → (α × α)",
({}: Protocol.EnvAddResult) value := "λ (α : Type u) (x : α) => (x, x)",
step "env.inspect" ({name := name3} : Protocol.EnvInspect) isTheorem := false
({ }: Protocol.EnvAdd)
type := { pp? := .some "(α : Type u) → αα × α" }, ({}: Protocol.EnvAddResult),
}: Protocol.EnvInspectResult) step "env.inspect" ({name := name3} : Protocol.EnvInspect)
({
type := { pp? := .some "(α : Type u) → αα × α" },
}:
Protocol.EnvInspectResult),
]
example : ∀ (p: Prop), p → p := by example : ∀ (p: Prop), p → p := by
intro p h intro p h
exact h exact h
def test_frontend_process : Test := do def test_frontend_process : Test :=
let file := "example : ∀ (p q: Prop), p → p q := by\n intro p q h\n exact Or.inl h" let file := "example : ∀ (p q: Prop), p → p q := by\n intro p q h\n exact Or.inl h"
let goal1 := "p q : Prop\nh : p\n⊢ p q" let goal1 := "p q : Prop\nh : p\n⊢ p q"
IO.FS.withTempDir λ tempdir => do [
let filename := s!"{tempdir}/invocations.jsonl" step "frontend.process"
step "frontend.process" ({
({ file? := .some file,
file? := .some file, invocations := true,
invocations? := .some filename, }: Protocol.FrontendProcess)
}: Protocol.FrontendProcess) ({
({ units := [{
units := [{ boundary := (0, file.utf8ByteSize),
boundary := (0, file.utf8ByteSize), invocations? := .some [
nInvocations? := .some 2, {
}], goalBefore := "⊢ ∀ (p q : Prop), p → p q",
}: Protocol.FrontendProcessResult) goalAfter := goal1,
stepFile (α := Protocol.FrontendData) "invocations" filename tactic := "intro p q h",
{ units := [{ usedConstants := #[],
invocations? := .some [ },
{ {
goalBefore := "⊢ ∀ (p q : Prop), p → p q", goalBefore := goal1 ,
goalAfter := goal1, goalAfter := "",
tactic := "intro p q h", tactic := "exact Or.inl h",
usedConstants := #[], usedConstants := #["Or.inl"],
}, },
{ ]
goalBefore := goal1 , }],
goalAfter := "", }: Protocol.FrontendProcessResult),
tactic := "exact Or.inl h", ]
usedConstants := #["Or.inl"],
},
]
} ] }
example : 1 + 2 = 3 := rfl example : 1 + 2 = 3 := rfl
example (p: Prop): p → p := by simp example (p: Prop): p → p := by simp
def test_frontend_process_sorry : Test := do def test_frontend_process_sorry : Test :=
let solved := "example : 1 + 2 = 3 := rfl\n" let solved := "example : 1 + 2 = 3 := rfl\n"
let withSorry := "example (p: Prop): p → p := sorry" let withSorry := "example (p: Prop): p → p := sorry"
let file := s!"{solved}{withSorry}" [
let goal1: Protocol.Goal := { let file := s!"{solved}{withSorry}"
name := "_uniq.6", let goal1: Protocol.Goal := {
target := { pp? := .some "p → p" }, name := "_uniq.6",
vars := #[{ name := "_uniq.4", userName := "p", type? := .some { pp? := .some "Prop" }}], target := { pp? := .some "p → p" },
} vars := #[{ name := "_uniq.4", userName := "p", type? := .some { pp? := .some "Prop" }}],
step "frontend.process" }
({ step "frontend.process"
file? := .some file, ({
sorrys := true, file? := .some file,
}: Protocol.FrontendProcess) sorrys := true,
({ }: Protocol.FrontendProcess)
units := [{ ({
boundary := (0, solved.utf8ByteSize), units := [{
}, { boundary := (0, solved.utf8ByteSize),
boundary := (solved.utf8ByteSize, solved.utf8ByteSize + withSorry.utf8ByteSize), }, {
goalStateId? := .some 0, boundary := (solved.utf8ByteSize, solved.utf8ByteSize + withSorry.utf8ByteSize),
goals? := .some #[goal1], goalStateId? := .some 0,
goalSrcBoundaries? := .some #[(57, 62)], goals? := .some #[goal1],
messages := #["<anonymous>:2:0: warning: declaration uses 'sorry'\n"], goalSrcBoundaries? := .some #[(57, 62)],
}], messages := #["<anonymous>:2:0: warning: declaration uses 'sorry'\n"],
}: Protocol.FrontendProcessResult) }],
}: Protocol.FrontendProcessResult),
]
def test_import_open : Test := do def test_import_open : Test :=
let header := "import Init\nopen Nat\nuniverse u" let header := "import Init\nopen Nat\nuniverse u"
let goal1: Protocol.Goal := { let goal1: Protocol.Goal := {
name := "_uniq.67", name := "_uniq.67",
target := { pp? := .some "n + 1 = n.succ" }, target := { pp? := .some "n + 1 = n.succ" },
vars := #[{ name := "_uniq.66", userName := "n", type? := .some { pp? := .some "Nat" }}], vars := #[{ name := "_uniq.66", userName := "n", type? := .some { pp? := .some "Nat" }}],
} }
step "frontend.process" [
({ step "frontend.process"
file? := .some header, ({
readHeader := true, file? := .some header,
inheritEnv := true, readHeader := true,
}: Protocol.FrontendProcess) inheritEnv := true,
({ }: Protocol.FrontendProcess)
units := [ ({
{ boundary := (12, 21) }, units := [
{ boundary := (21, header.utf8ByteSize) }, { boundary := (12, 21) },
], { boundary := (21, header.utf8ByteSize) },
}: Protocol.FrontendProcessResult) ],
step "goal.start" ({ expr := "∀ (n : Nat), n + 1 = Nat.succ n"} : Protocol.GoalStart) }: Protocol.FrontendProcessResult),
({ stateId := 0, root := "_uniq.65" }: Protocol.GoalStartResult) step "goal.start" ({ expr := "∀ (n : Nat), n + 1 = Nat.succ n"} : Protocol.GoalStart)
step "goal.tactic" ({ stateId := 0, tactic? := .some "intro n" }: Protocol.GoalTactic) ({ stateId := 0, root := "_uniq.65" }: Protocol.GoalStartResult),
({ nextStateId? := .some 1, goals? := #[goal1], }: Protocol.GoalTacticResult) step "goal.tactic" ({ stateId := 0, tactic? := .some "intro n" }: Protocol.GoalTactic)
step "goal.tactic" ({ stateId := 1, tactic? := .some "apply add_one" }: Protocol.GoalTactic) ({ nextStateId? := .some 1, goals? := #[goal1], }: Protocol.GoalTacticResult),
({ nextStateId? := .some 2, goals? := .some #[], }: Protocol.GoalTacticResult) step "goal.tactic" ({ stateId := 1, tactic? := .some "apply add_one" }: Protocol.GoalTactic)
step "goal.start" ({ expr := "∀ (x : Sort u), Sort (u + 1)"} : Protocol.GoalStart) ({ nextStateId? := .some 2, goals? := .some #[], }: Protocol.GoalTacticResult),
({ stateId := 3, root := "_uniq.5" }: Protocol.GoalStartResult) step "goal.start" ({ expr := "∀ (x : Sort u), Sort (u + 1)"} : Protocol.GoalStart)
({ stateId := 3, root := "_uniq.5" }: Protocol.GoalStartResult),
]
/-- Ensure there cannot be circular references -/ /-- Ensure there cannot be circular references -/
def test_frontend_process_circular : Test := do def test_frontend_process_circular : Test :=
let withSorry := "theorem mystery : 1 + 2 = 2 + 3 := sorry" let withSorry := "theorem mystery : 1 + 2 = 2 + 3 := sorry"
let goal1: Protocol.Goal := { [
name := "_uniq.2", let goal1: Protocol.Goal := {
target := { pp? := .some "1 + 2 = 2 + 3" }, name := "_uniq.2",
vars := #[], target := { pp? := .some "1 + 2 = 2 + 3" },
} vars := #[],
step "frontend.process" }
({ step "frontend.process"
file? := .some withSorry, ({
sorrys := true, file? := .some withSorry,
}: Protocol.FrontendProcess) sorrys := true,
({ }: Protocol.FrontendProcess)
units := [{ ({
boundary := (0, withSorry.utf8ByteSize), units := [{
goalStateId? := .some 0, boundary := (0, withSorry.utf8ByteSize),
goals? := .some #[goal1], goalStateId? := .some 0,
goalSrcBoundaries? := .some #[(35, 40)], goals? := .some #[goal1],
messages := #["<anonymous>:1:8: warning: declaration uses 'sorry'\n"], goalSrcBoundaries? := .some #[(35, 40)],
}], messages := #["<anonymous>:1:8: warning: declaration uses 'sorry'\n"],
}: Protocol.FrontendProcessResult) }],
step "goal.tactic" ({ stateId := 0, tactic? := .some "exact?" }: Protocol.GoalTactic) }: Protocol.FrontendProcessResult),
({ messages? := .some #["`exact?` could not close the goal. Try `apply?` to see partial suggestions."] } step "goal.tactic" ({ stateId := 0, tactic? := .some "exact?" }: Protocol.GoalTactic)
: Protocol.GoalTacticResult) ({ messages? := .some #["`exact?` could not close the goal. Try `apply?` to see partial suggestions."] }
: Protocol.GoalTacticResult),
]
def runTestSuite (env : Lean.Environment) (steps : Test): IO LSpec.TestSeq := do def runTest (env: Lean.Environment) (steps: Test): IO LSpec.TestSeq := do
-- Setup the environment for execution -- Setup the environment for execution
let coreContext ← createCoreContext #[] let coreContext ← createCoreContext #[]
let mainM : MainM LSpec.TestSeq := runTest steps let mainM : MainM LSpec.TestSeq :=
steps.foldlM (λ suite step => do return suite ++ (← step)) LSpec.TestSeq.done
mainM.run { coreContext } |>.run' { env } mainM.run { coreContext } |>.run' { env }
def suite (env : Lean.Environment): List (String × IO LSpec.TestSeq) := def suite (env : Lean.Environment): List (String × IO LSpec.TestSeq) :=
@ -349,7 +357,7 @@ def suite (env : Lean.Environment): List (String × IO LSpec.TestSeq) :=
("frontend.process import", test_import_open), ("frontend.process import", test_import_open),
("frontend.process circular", test_frontend_process_circular), ("frontend.process circular", test_frontend_process_circular),
] ]
tests.map (fun (name, test) => (name, runTestSuite env test)) tests.map (fun (name, test) => (name, runTest env test))
end Pantograph.Test.Integration end Pantograph.Test.Integration