Zulip Chat Archive

Stream: lean4

Topic: Pass optional syntax in macro


Patrick Massot (Jul 15 2023 at 15:18):

In the following code, a call to tactic bar is meant to expand to the same call to foo. But I don't know how to pass the optional syntax. Both variations below fail.

open Lean Parser Tactic

macro "foo" (location)? : tactic => `(tactic|done)

macro "bar" loc:(location)? : tactic => `(tactic|foo $loc)

macro "bar" loc:(location)? : tactic => `(tactic|foo $(mkOptionalNode loc))

Mac Malone (Jul 15 2023 at 15:32):

@Patrick Massot $[...]? is used for optional syntax:

macro "bar" loc?:(location)? : tactic => `(tactic|foo $[$loc?]?)

Patrick Massot (Jul 15 2023 at 15:37):

Thanks a lot. It almost work in my real use case. It fails in the presence of a mysterious & in the original syntax;

Patrick Massot (Jul 15 2023 at 15:38):

Something like

macro "foo" (&"baz")? (location)? : tactic => `(tactic|done)

macro "bar" ba:(&"baz")? loc:(location)? : tactic => `(tactic|foo $[$ba]? $[$loc]?)

Sebastian Ullrich (Jul 15 2023 at 15:53):

The syntax for individual tokens is a bit different

macro "bar" ba:(&"baz")? loc:(location)? : tactic => `(tactic|foo $[baz%$ba]? $[$loc]?)

Patrick Massot (Jul 15 2023 at 16:00):

Thanks!

Patrick Massot (Jul 15 2023 at 16:21):

Next I need to remember how to write a macro which expand to several tactic calls, fighting the difference between tactic and tactic_seq.

Patrick Massot (Jul 15 2023 at 16:22):

Say I want to add done after foo $[baz%$ba]? $[$loc]?, how do I do that?

Sebastian Ullrich (Jul 15 2023 at 16:24):

You can use parentheses to turn a tactic sequence into a single tactic

Patrick Massot (Jul 15 2023 at 16:25):

I knew there was a simple trick but I couldn't remember it. Thanks!

Patrick Massot (Nov 03 2023 at 00:45):

I hit again the same issue as in July but I can't get the above answer to work. If have a tactic whose definition starts with

elab tok:"rw_ineq" rules:rwRuleSeq loc:(location)? withArg:((" with " (colGt binderIdent)+)?) : tactic =>

and I want a macro rwa_ineq with the exact same syntax that call rw_ineq and then assumption. I tried

macro "rwa_ineq " rws:rwRuleSeq loc:(location)? withArg:(" with " (colGt binderIdent)+)? : tactic =>
  `(tactic| (rw_ineq $rws:rwRuleSeq $[$loc:location]? $[$withArg:location]?; assumption))

but that doesn't work.

Full code is

import Lean

open Lean Parser Meta Elab Term Tactic

elab tok:"rw_ineq" rules:rwRuleSeq loc:(location)? withArg:((" with " (colGt Lean.binderIdent)+)?) : tactic =>
  pure ()

macro "rwa_ineq " rws:rwRuleSeq loc:(location)? withArg:(" with " (colGt Lean.binderIdent)+)? : tactic =>
  `(tactic| (rw_ineq $rws:rwRuleSeq $[$loc:location]? $[$withArg:location]?; assumption))

Kyle Miller (Nov 03 2023 at 00:56):

Here's one way:

import Lean

open Lean Parser Meta Elab Term Tactic

syntax withClause := " with " (colGt Lean.binderIdent)?

elab tok:"rw_ineq" rules:rwRuleSeq loc:(location)? withArg:(withClause)? : tactic =>
  pure ()

macro "rwa_ineq " rws:rwRuleSeq loc:(location)? withArg:(withClause)? : tactic =>
  `(tactic| (rw_ineq $rws:rwRuleSeq $[$loc:location]? $[$withArg]?; assumption))

Kyle Miller (Nov 03 2023 at 00:58):

Here's another:

import Lean

open Lean Parser Meta Elab Term Tactic

elab tok:"rw_ineq" rules:rwRuleSeq loc:(location)? withArg:((" with " (colGt Lean.binderIdent)+)?) : tactic =>
  pure ()

syntax "rwa_ineq " rwRuleSeq (location)? (" with " (colGt Lean.binderIdent)+)? : tactic

macro_rules
  | `(tactic| rwa_ineq $rws $[$loc]? $[with $args*]?) =>
    `(tactic| rw_ineq $rws $[$loc]? $[with $args*]?)

Patrick Massot (Nov 03 2023 at 01:00):

Great, the first solution works (with minor ajustements to the code)! Thanks!

Patrick Massot (Nov 03 2023 at 01:01):

I'm still curious to understand why my original code didn't work (and it would be really great to have any of this documented somewhere).


Last updated: Dec 20 2023 at 11:08 UTC