fix: don't change antiquotations semantics in do if

This commit is contained in:
Sebastian Ullrich 2020-12-20 16:59:24 +01:00
parent a56fd6a8c0
commit 90f747e346
3 changed files with 14 additions and 11 deletions

View file

@ -627,18 +627,19 @@ def mkSingletonDoSeq (doElem : Syntax) : Syntax :=
/-
If the given syntax is a `doIf`, return an equivalente `doIf` that has an `else` but no `else if`s or `let if`s. -/
private def expandDoIf? (stx : Syntax) : MacroM (Option Syntax) := match stx with
| `(doElem|if $cond then $t else $e) => pure none
| `(doElem|if $cond then $t $[else if $conds then $ts]* $[else $e?]?) => withRef stx do
| `(doElem|if $p:doIfProp then $t else $e) => pure none
| `(doElem|if $cond:doIfCond then $t $[else if $conds:doIfCond then $ts]* $[else $e?]?) => go cond t conds ts e?
| _ => pure none
where go cond t conds ts e? := withRef stx do
let mut e := e?.getD (← `(doSeq|pure PUnit.unit))
let mut eIsSeq := true
for (cond, t) in (conds.reverse.push cond).zip (ts.reverse.push t) do
e ← if eIsSeq then e else `(doSeq|$e:doElem)
e ← withRef cond <| match cond with
| `(doIfLet|let $pat := $d) => `(doElem|match $d:term with | $pat:term => $t | _ => $e)
| _ => `(doElem|if $cond then $t else $e)
| `(doIfCond|let $pat := $d) => `(doElem|match $d:term with | $pat:term => $t | _ => $e)
| _ => `(doElem|if $cond:doIfCond then $t else $e)
eIsSeq := false
return some e
| _ => pure none
structure DoIfView where
ref : Syntax

View file

@ -78,11 +78,13 @@ else if c_2 then
```
-/
def elseIf := atomic (group (withPosition (" else " >> checkLineEq >> " if ")))
def doIfLet := parser! "let " >> termParser >> " := " >> termParser
def doIfCond := parser! optIdent >> termParser
-- ensure `if $e then ...` still binds to `e:term`
def doIfLet := nodeWithAntiquot "doIfLet" `Lean.Parser.Term.doIfLet <| "let " >> termParser >> " := " >> termParser
def doIfProp := nodeWithAntiquot "doIfProp" `Lean.Parser.Term.doIfProp <| optIdent >> termParser
def doIfCond := withAntiquot (mkAntiquot "doIfCond" none (anonymous := false)) <| doIfLet <|> doIfProp
@[builtinDoElemParser] def doIf := parser! withPosition $
"if " >> (doIfLet <|> doIfCond) >> " then " >> doSeq
>> many (checkColGe "'else if' in 'do' must be indented" >> group (elseIf >> (doIfLet <|> doIfCond) >> " then " >> doSeq))
"if " >> doIfCond >> " then " >> doSeq
>> many (checkColGe "'else if' in 'do' must be indented" >> group (elseIf >> doIfCond >> " then " >> doSeq))
>> optional (checkColGe "'else' in 'do' must be indented" >> " else " >> doSeq)
@[builtinDoElemParser] def doUnless := parser! "unless " >> withForbidden "do" termParser >> "do " >> doSeq
def doForDecl := parser! termParser >> " in " >> withForbidden "do" termParser

View file

@ -17,7 +17,7 @@ syntax "while " termBeforeDo " do " doSeq : doElem
macro_rules
| `(doElem| while $cond do $seq) =>
`(doElem| repeat if $cond:term then $seq else break)
`(doElem| repeat if $cond then $seq else break)
def test1 : IO Unit := do
let mut i := 0
@ -32,7 +32,7 @@ syntax "repeat " doSeq " until " term : doElem
macro_rules
| `(doElem| repeat $seq until $cond) =>
`(doElem| repeat do $seq; if $cond:term then break)
`(doElem| repeat do $seq; if $cond then break)
def test2 : IO Unit := do
let mut i := 0