Zulip Chat Archive
Stream: new members
Topic: How do I write a "#check_syntax"?
Eduardo Ochs (May 16 2024 at 02:45):
Hi all,
I'm taking far too long to do this myself, so I decided to ask...
In the section "Free form syntax declarations" of the metaprogramming book there's an example - inside "namespace Playground2" - in which the command "#check_failure ⊥ OR (⊤ AND ⊥)" fails with the error "elaboration function for 'Playground2.term_OR_' has not been implemented". I only found that error message in two places in the source:
here in Lean/Elab/Command.lean, and
here in Lean/Elab/Term.lean,
but lots of things happen before that error message...
How do I write a variant of #check or #check_failure - let me call that variant "#check_syntax" - that parses the rest of the line like #check or #check_failure, i.e., like this,
@[builtin_command_parser] def check := leading_parser "#check " >> termParser
but that does not try to elaborate the result of "termParser"? I would like it to just print the resulting Syntax object...
Eric Wieser (May 16 2024 at 02:50):
I usually use #check `(my_custom_syntax)
for this
Eduardo Ochs (May 16 2024 at 03:03):
Neat! If I run this,
#check `(42 + "foo")
then the output is:
do
let info ← Lean.MonadRef.mkInfoFromRefPos
let scp ← Lean.getCurrMacroScope
let mainModule ← Lean.getMainModule
pure
{
raw :=
Lean.Syntax.node3 info `term_+_ (Lean.Syntax.node1 info `num (Lean.Syntax.atom info "42"))
(Lean.Syntax.atom info "+")
(Lean.Syntax.node1 info `str (Lean.Syntax.atom info "\"foo\"")) } : ?m.233 (Lean.TSyntax `term) (lsp)
Eduardo Ochs (May 16 2024 at 03:04):
I would still like to learn how to write a new command that works as the first half of #check, but that helps!
Kyle Miller (May 16 2024 at 03:08):
Here:
namespace Playground2
scoped syntax "⊥" : term -- ⊥ for false
scoped syntax "⊤" : term -- ⊤ for true
scoped syntax:40 term " OR " term : term
scoped syntax:50 term " AND " term : term
elab "#check_syntax " t:term : command => do
Lean.logInfo m!"{t}"
#check_syntax ⊥ OR (⊤ AND ⊥)
-- ⊥ OR (⊤ AND ⊥)
end Playground2
Kyle Miller (May 16 2024 at 03:08):
It doesn't look like it's doing anything, but it's parsing the syntax (getting a Syntax
) and then printing that Syntax
back out.
Kyle Miller (May 16 2024 at 03:10):
If you change the logging line to Lean.logInfo m!"{repr t.raw}"
you can see the structure of the Syntax
.
Eduardo Ochs (May 16 2024 at 07:05):
Fantastic! Many thanks! :upside_down::upside_down::upside_down:
If anyone else is reading this, here is a version that is trivial to run:
import Lean.Elab.Command
namespace Playground2
scoped syntax "⊥" : term
scoped syntax "⊤" : term
scoped syntax:40 term " OR " term : term
scoped syntax:50 term " AND " term : term
elab "#check_syntax " t:term : command => do Lean.logInfo m!"{t}"
elab "#check_syntax " t:term : command => do Lean.logInfo m!"{repr t.raw}"
#check_syntax ⊥ OR (⊤ AND ⊥)
end Playground2
The definition of "#check_syntax" that holds is the last one - to change its behavior, reorder the "elab" lines.
Eduardo Ochs (May 17 2024 at 06:37):
(deleted)
Last updated: May 02 2025 at 03:31 UTC