lean4-htt/src/Lean/Elab/BindersUtil.lean
Leonardo de Moura 6d926c7989 feat: macro expand match alternatives
see #371

This commit does not implement all features discussed in this issue.
It has implemented it as a macro expansion. Thus, the following is
accepted
```lean
inductive StrOrNum where
  | S (s : String)
  | I (i : Int)

def StrOrNum.asString (x : StrOrNum) :=
  match x with
  | I a | S a => toString a
```
It may confuse the Lean LSP server. The `a` on `toString` shows the
information for the first alternative after expansion (i.e., `a` is an `Int`).
After expansion, we have
```
def StrOrNum.asString (x : StrOrNum) :=
  match x with
  | I a => toString a
  | S a => toString a
```
2022-03-20 14:20:13 -07:00

57 lines
1.6 KiB
Text

/-
Copyright (c) 2021 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Leonardo de Moura
-/
import Lean.Parser.Term
namespace Lean.Elab.Term
/-
Recall that
```
def typeSpec := leading_parser " : " >> termParser
def optType : Parser := optional typeSpec
```
-/
def expandOptType (ref : Syntax) (optType : Syntax) : Syntax :=
if optType.isNone then
mkHole ref
else
optType[0][1]
open Lean.Parser.Term
/- Helper function for `expandEqnsIntoMatch` -/
def getMatchAltsNumPatterns (matchAlts : Syntax) : Nat :=
let alt0 := matchAlts[0][0]
let pats := alt0[1][0].getSepArgs
pats.size
/--
Expand a match alternative such as `| 0 | 1 => rhs` to an array containing `| 0 => rhs` and `| 1 => rhs`.
-/
def expandMatchAlt (stx : Syntax) : MacroM (Array Syntax) :=
match stx with
| `(matchAltExpr| | $[$patss]|* => $rhs) =>
if patss.size ≤ 1 then
return #[stx]
else
patss.mapM fun pats => let pats := #[pats]; `(matchAltExpr| | $[$pats]|* => $rhs)
| _ => return #[stx]
def shouldExpandMatchAlt (matchAlt : Syntax) : Bool :=
match matchAlt with
| `(matchAltExpr| | $[$patss]|* => $rhs) => patss.size > 1
| _ => false
def expandMatchAlts? (stx : Syntax) : MacroM (Option Syntax) := do
match stx with
| `(match $[$gen]? $[$motive]? $discrs,* with $alts:matchAlt*) =>
if alts.any shouldExpandMatchAlt then
let alts ← alts.foldlM (init := #[]) fun alts alt => return alts ++ (← expandMatchAlt alt)
`(match $[$gen]? $[$motive]? $discrs,* with $alts:matchAlt*)
else
return none
| _ => return none
end Lean.Elab.Term