feat: support while let in do blocks via unified condition syntax (#13534)
This PR generalizes the `while` syntax in `do` blocks so that the condition can be any `doIfCond`, the same condition form already accepted by `if`. As a result, `while let pat := e do …` and `while let pat ← e do …` are now supported in addition to `while cond do …` and `while h : cond do …`. The previously separate `doWhile` and `doWhileH` parsers and their accompanying macros are unified into a single `doWhile` parser whose macro delegates to the existing `doIf` desugaring.
This commit is contained in:
parent
3c6317b6d7
commit
4d7b7dd8e6
4 changed files with 71 additions and 8 deletions
|
|
@ -36,12 +36,8 @@ remove the following code without breaking the do block's type.
|
|||
Term.withMacroExpansion stx expanded <|
|
||||
withRef expanded <| elabDoElem ⟨expanded⟩ dec
|
||||
|
||||
@[builtin_macro Lean.Parser.Term.doWhileH] def expandDoWhileH : Macro
|
||||
| `(doElem| while%$tk $h : $cond do $seq) => `(doElem| repeat%$tk if $h:ident : $cond then $seq else break)
|
||||
| _ => Macro.throwUnsupported
|
||||
|
||||
@[builtin_macro Lean.Parser.Term.doWhile] def expandDoWhile : Macro
|
||||
| `(doElem| while%$tk $cond do $seq) => `(doElem| repeat%$tk if $cond then $seq else break)
|
||||
| `(doElem| while%$tk $cond:doIfCond do $seq) => `(doElem| repeat%$tk if $cond:doIfCond then $seq else break)
|
||||
| _ => Macro.throwUnsupported
|
||||
|
||||
@[builtin_macro Lean.Parser.Term.doRepeatUntil] def expandDoRepeatUntil : Macro
|
||||
|
|
|
|||
|
|
@ -275,10 +275,8 @@ with debug assertions enabled (see the `debugAssertions` option).
|
|||
|
||||
@[builtin_doElem_parser] def doRepeat := leading_parser
|
||||
"repeat " >> doSeq
|
||||
@[builtin_doElem_parser] def doWhileH := leading_parser
|
||||
"while " >> ident >> " : " >> withForbidden "do" termParser >> " do " >> doSeq
|
||||
@[builtin_doElem_parser] def doWhile := leading_parser
|
||||
"while " >> withForbidden "do" termParser >> " do " >> doSeq
|
||||
"while " >> withForbidden "do" doIfCond >> " do " >> doSeq
|
||||
@[builtin_doElem_parser] def doRepeatUntil := leading_parser
|
||||
"repeat " >> doSeq >> ppDedent ppLine >> "until " >> termParser
|
||||
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ options get_default_options() {
|
|||
// Temporary, core-only flags for editing (i.e. must be part of stage0/bin/lean). Must be synced
|
||||
// with `LEAN_EXTRA_MAKE_OPTS` build flags in src/CMakeLists.txt.
|
||||
opts = opts.update({"backward", "do", "legacy"}, false);
|
||||
// trigger stage0 update: unify `while` parser via `doIfCond`
|
||||
#endif
|
||||
return opts;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -48,3 +48,71 @@ test3 done 12
|
|||
-/
|
||||
#guard_msgs in
|
||||
#eval test3
|
||||
|
||||
-- `while let pat := e do ...` exits when the pattern fails to match.
|
||||
def testWhileLet : IO Unit := do
|
||||
let mut xs := [0, 1, 2, 3]
|
||||
while let x :: rest := xs do
|
||||
println! "{x}"
|
||||
xs := rest
|
||||
println! "done {xs.length}"
|
||||
|
||||
/--
|
||||
info: 0
|
||||
1
|
||||
2
|
||||
3
|
||||
done 0
|
||||
-/
|
||||
#guard_msgs in
|
||||
#eval testWhileLet
|
||||
|
||||
-- `while let pat ← e do ...` evaluates the bind on each iteration.
|
||||
def testWhileLetBind : IO Unit := do
|
||||
let mut xs := [0, 1, 2, 3]
|
||||
while let some x ← pure xs.head? do
|
||||
println! "{x}"
|
||||
xs := xs.tail
|
||||
println! "done"
|
||||
|
||||
/--
|
||||
info: 0
|
||||
1
|
||||
2
|
||||
3
|
||||
done
|
||||
-/
|
||||
#guard_msgs in
|
||||
#eval testWhileLetBind
|
||||
|
||||
-- Pops entries from an `IO.Ref`-backed list to show that the bound expression
|
||||
-- in `while let pat ← e do ...` is re-evaluated each iteration.
|
||||
def testWhileLetBindRef : IO Unit := do
|
||||
let r ← IO.mkRef [0, 1, 2, 3]
|
||||
while let x :: rest ← r.get do
|
||||
println! "{x}"
|
||||
r.set rest
|
||||
println! "done {(← r.get).length}"
|
||||
|
||||
/--
|
||||
info: 0
|
||||
1
|
||||
2
|
||||
3
|
||||
done 0
|
||||
-/
|
||||
#guard_msgs in
|
||||
#eval testWhileLetBindRef
|
||||
|
||||
-- Unified `while` keeps supporting the `while h : cond do ...` form.
|
||||
def testWhileH (xs : Array Nat) : Nat := Id.run do
|
||||
let mut i := 0
|
||||
let mut sum := 0
|
||||
while h : i < xs.size do
|
||||
sum := sum + xs[i]
|
||||
i := i + 1
|
||||
return sum
|
||||
|
||||
/-- info: 6 -/
|
||||
#guard_msgs in
|
||||
#eval testWhileH #[1, 2, 3]
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue