feat: parenthesizer: support antiquotations

This commit is contained in:
Sebastian Ullrich 2020-05-24 16:17:15 +02:00
parent b35b973a5d
commit 48246c8e4a
2 changed files with 27 additions and 15 deletions

View file

@ -1423,8 +1423,8 @@ def pushNone : Parser :=
{ fn := fun c s => s.pushSyntax mkNullNode }
-- We support two kinds of antiquotations: `$id` and `$(t)`, where `id` is a term identifier and `t` is a term.
private def antiquotNestedExpr : Parser := node `antiquotNestedExpr ("(" >> termParser >> ")")
private def antiquotExpr : Parser := identNoAntiquot <|> antiquotNestedExpr
def antiquotNestedExpr : Parser := node `antiquotNestedExpr ("(" >> termParser >> ")")
def antiquotExpr : Parser := identNoAntiquot <|> antiquotNestedExpr
/--
Define parser for `$e` (if anonymous == true) and `$e:name`. Both

View file

@ -76,6 +76,7 @@ the left. `visitArgs x` executes `x` on the right-most child of the current node
prelude
import Init.Lean.Parser
import Init.Lean.Elab.Command
import Init.Lean.Elab.Quotation
import Init.Lean.Delaborator
namespace Lean
@ -195,6 +196,13 @@ instance ParenthesizerM.monadTraverser : Syntax.MonadTraverser ParenthesizerM :=
open Syntax.MonadTraverser
/-- Execute `x` at the right-most child of the current node, if any, then advance to the left. -/
def visitArgs (x : ParenthesizerM Unit) : ParenthesizerM Unit := do
stx ← getCur;
when (stx.getArgs.size > 0) $
goDown (stx.getArgs.size - 1) *> x <* goUp;
goLeft
/--
Call an appropriate `[parenthesizer]` depending on the `Parser` `Expr` `p`. After the call, the traverser position
should be to the left of all nodes produced by `p`, or at the left-most child if there are no other nodes left. -/
@ -225,6 +233,17 @@ instance monadQuotation : MonadQuotation ParenthesizerM := {
withFreshMacroScope := fun α x => x,
}
def visitAntiquot : ParenthesizerM Unit := do
stx ← getCur;
if Elab.Term.Quotation.isAntiquot stx then visitArgs $ do
-- antiquot syntax is, simplified, `"$" "$"* antiquotExpr ":" (nonReservedSymbol name) "*"?`
goLeft; goLeft; goLeft; -- now on `antiquotExpr`
visit (mkConst `Lean.Parser.antiquotExpr);
-- set precedence; see special case in `currLbp`
modify (fun st => { st with firstLbp := Parser.appPrec, minLbp := Parser.appPrec })
else
throw $ Exception.other $ "not an antiquotation"
/-- Recurse using `visit`, and parenthesize the result using `mkParen` if necessary. -/
def visitParenthesizable (mkParen : Syntax → Syntax) (rbp : Nat) : ParenthesizerM Unit := do
stx ← getCur;
@ -271,13 +290,6 @@ def visitToken (lbp : Nat) : ParenthesizerM Unit := do
modify (fun st => { st with firstLbp := lbp });
goLeft
/-- Execute `x` at the right-most child of the current node, if any, then advance to the left. -/
def visitArgs (x : ParenthesizerM Unit) : ParenthesizerM Unit := do
stx ← getCur;
when (stx.getArgs.size > 0) $
goDown (stx.getArgs.size - 1) *> x <* goUp;
goLeft
def evalNat (e : Expr) : ParenthesizerM Nat := do
e ← liftM $ whnf e;
some n ← pure $ Meta.evalNat e
@ -317,23 +329,23 @@ lbp ← evalNat p.appArg!;
visitParenthesizable (fun stx => Unhygienic.run `(($stx))) lbp
@[builtinParenthesizer tacticParser]
def tacticParser.parenthesizer : Parenthesizer | p => do
def tacticParser.parenthesizer : Parenthesizer | p => visitAntiquot <|> do
lbp ← evalNat p.appArg!;
visitParenthesizable (fun stx => Unhygienic.run `(tactic|($stx))) lbp
@[builtinParenthesizer levelParser]
def levelParser.parenthesizer : Parenthesizer | p => do
def levelParser.parenthesizer : Parenthesizer | p => visitAntiquot <|> do
lbp ← evalNat p.appArg!;
visitParenthesizable (fun stx => Unhygienic.run `(level|($stx))) lbp
@[builtinParenthesizer commandParser]
def commandParser.parenthesizer : Parenthesizer | p => do
@[builtinParenthesizer categoryParser]
def categoryParser.parenthesizer : Parenthesizer | p => visitAntiquot <|> do
stx ← getCur;
visit (mkConst stx.getKind)
@[builtinParenthesizer withAntiquot]
def withAntiquot.parenthesizer : Parenthesizer | p =>
visit (p.getArg! 1)
visitAntiquot <|> visit (p.getArg! 1)
@[builtinParenthesizer try]
def try.parenthesizer : Parenthesizer | p =>
@ -374,7 +386,7 @@ visitArgs $ do {
| panic! "trailingNode.parenthesizer: visited a trailing term without tokens?!";
{ mkParen := some mkParen, .. } ← read
| panic! "trailingNode.parenthesizer called outside of visitParenthesizable call";
visitParenthesizable mkParen 0;
visitAntiquot <|> visitParenthesizable mkParen 0;
modify $ fun st => { st with minLbp := Nat.min (st.minLbp.getD (lbp - 1)) (lbp - 1) }
}