blob: 08be3555ee6b3c8b86a243d690cc4868893924c7 [file] [edit]
import Lean
/-!
# Parser error recovery
This test is to make sure that the error recovery feature is working as intended. In particular, it
checks that certain errors in the head of a declaration (e.g. an invalid name) don't prevent further
parse errors from being reported.
-/
open Lean Parser
/-!
## Error recovery for Lean commands
-/
def "foo" (x : Nat) : := 5
def 5 : Nat := 3
theorem yep : True := by trivial
theorem () : Nat := 99
theorem 2.4 : Nat := )
theorem "nat" : Nat := )
theorem 3 : Nat := )
opaque ((( : Nat := )
axiom "nope" : 4 = ⟩
class inductive () where
| "" : )
inductive 44: Type where | "" : 44
inductive 44 : Type where | "" : 44
inductive 44 (n : Nat) : Type where | "" : 44
inductive 44(n : Nat) : Type where | "" : 44
inductive 44| "" : 44
inductive !!! where
| "" (x : Nat)) : Bogus
#eval Foo.a
inductive Item.{4, 5, 6, 7, a, "foo", b, c} : Nat where
| foo : )
| bar : )
example := ""
/-!
## Error recovery for custom syntax
Adding recovery to Lean's term grammar doesn't work well with the primitive tools at hand
(extensibility + token tables + backtracking are a real challenge), but for DSLs it can be useful.
This tests that error recovery works for a term syntax extension.
-/
def altParen : Parser :=
"{|" >> termParser (prec := 51) >> recover "|}" skip
macro:50 e:altParen : term => pure ⟨e.raw[1]⟩
-- These terms show multiple errors due to recovery from missing |} tokens
#eval ([ {|2 + 3] * {| 3 + |}
-- Only one error here
#eval ([ (2 + 3] * ( 3 + ) )
example := ""
/-!
## Error recovery for custom commands
This command can recover from many parse errors. Make sure that there's no arbitrary small limit by
testing a few recoveries.
-/
def nonws : Parser where
fn :=
andthenFn
(andthenFn (satisfyFn (fun c => !c.isWhitespace && c != '#')) (takeWhileFn (!·.isWhitespace)))
whitespace
def thing : Parser :=
recover ident nonws
open Lean Elab Command in
elab "#go " xs:thing* (Lean.Parser.eoi <|> "#stop") : command => do
let xs := toString xs
elabCommand <| ← `(#eval s!"hey {$(quote xs)}")
-- Many errors due to recovery!
#go
hey
5
a
g
def
5
hey
( 99
(
#stop
-- Even though the command had errors, this is still running as expected:
def x := 5
#eval x