-
Notifications
You must be signed in to change notification settings - Fork 460
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Typed Macros #1251
Typed Macros #1251
Conversation
…ct antiquotations in `macro` and `elab`
Would be nice to generalize this at some point
It would be nice if `macro` was as expressive as syntax quotations, but right now it's not.
Most notable change: `Quote` is now parameterized by the target kind. Which means that `Name` etc. could actually have different implementations for quoting into `term` and `level`, if that need ever arises.
These are just the ones I stumbled upon, there should be a lot more now rendered obsolete by the coercions.
Sometimes there's just no structure to work on
The namespace `TSyntax.Compat` can be opened for a coercion `Syntax -> TSyntax k` for any `k`, as otherwise this PR would never be done.
It seems type information often flows from the body to the loop variable, which is problematic with coercions.
Automatically fixes many TSyntax type errors
And yes, this unapologetically breaks basically all the procedural Lean macros mentioning |
@Kha Quick short suggestion I had while pursuing the code: It would be nice to have some abbreviations for common abbrev Term := TSyntax `term
abbrev Command := TSyntax `command
abbrev Ident := TSyntax identKind
abbrev StrLit := TSyntax strLitKind
abbrev NumLit := TSyntax numLitKind
-- ... and more It would also save a lot of horizontal space in signatures. 😉 |
Yes, I think that's a good idea. They should probably go into |
src/Init/Meta.lean
Outdated
instance : Coe (TSyntax charLitKind) (TSyntax `term) where | ||
coe s := ⟨s.raw⟩ | ||
|
||
instance : Coe (TSyntax numLitKind) (TSyntax `prec) where | ||
coe s := ⟨s.raw⟩ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could make these instances "safe" by moving Unhygienic
into here so that we can do e.g. Unhygienic.run `(prec| $s:num)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could we add a command that automates this construction (presumably with some unconventional parser use)?
tsyntax_coe ident : declId
-- "expands" to
instance : Coe (TSyntax `ident) (TSyntax ``declId) where
coe s := Unhygienic.run `(declId|$s:ident)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I was deliberating/dreading that idea... :)
Can you explain what the list means? Is the syntax meant to be an element of all of the "kinds", or one of the "kinds", or something else entirely? (I'm putting "kind" in quotes here because it seems to refer to both node kinds as well as category names.) Maybe an example for when you need a non-singleton list would help as well. |
The run-time kind may be any of the given kinds. This is mostly relevant for parsers of the shape
|
An example for a choice of kinds and where coercions are doing a lot of work behind the secnes to translate syntax between contexts: let structInstFields ← letIdDecls.mapM fun
...
`(structInstField|$id:ident := $val)
let body ← `({ $structInstFields,* }) Without the coercion from argument
structInstFields
has type
Array (TSyntax `Lean.Parser.Term.structInstField) : Type
but is expected to have type
Syntax.TSepArray [`Lean.Parser.Term.structInstFieldAbbrev, `Lean.Parser.Term.structInstField] "," : Type |
Thank you for the explanation! Now the list makes sense. |
Thinking further on this, relaxing
without the need for Going further, since |
!bench |
Here are the benchmark results for commit 5b8d558. Benchmark Metric Change
============================================
- stdlib instructions 3% (1088.0 σ)
- stdlib task-clock 3% (722.9 σ)
- stdlib wall-clock 3% (33.6 σ)
- unionfind instructions 1% (147.4 σ) |
We're intending to merge this today unless there are objections. |
Compared to macro languages similar to Lean but with "simple" syntax structure such as Racket, optional syntax parts and slight syntactic variations are a frequent source of bugs in Lean macro programming resulting in ill-formed syntax trees.
The most robust solution to date, apart from learning the grammar by heart, was to excessively apply antiquotation kinds like
$e:term
and$id:ident
everywhere, which is not pleasant to read or write. However, Lean already has this handy feature called "types" (though they overdid it, I've heard) to detect ill-formed programs before running them, which this PR puts to use on the syntax manipulation level as well.The first example errors with the above when defining the macro, while the second one magically constructs the correct syntax tree now via a coercion from
TSyntax `ident
toTSyntax `Lean.Parser.Command.declId
.Main surface-level changes
TSyntax k
that represents a syntax tree of syntax kindk
TSepArray k sep
as well asTSyntaxArray k := Array (TSyntax k)
ks
of choices for the run-time syntax kind, though the singleton kind case is by far the most common and presented as above by a coercion and unexpanderInit.Meta
the grammar or something was the main reason I even embarked on this journey at this point!
Notably, the following fundamental parts did not change (yet) and still expect/produce
Syntax
:Lean.Macro
, as macros are currently unaware of the syntax category they are operating in (and mixing up syntax categories at the macro input/output boundary seems quite rare compared to errors like the above)match
, necessarily due to the aboveNotable implementation changes/refactorings
I've tried to categorize all the breakage after update-stage0 into different commits to give an idea as to what and how many changes are necessary to adapt existing code, as well as what could still be improved:
ddafed3 chore: changes to placate coercions
7 files changed, 13 insertions(+), 12 deletions(-)
596d0f2 refactor: make more use of quotations
Automatically fixes many TSyntax type errors
15 files changed, 96 insertions(+), 129 deletions(-)
c2fab9d chore: raw syntax kind accesses
Sometimes just checking the kind simply is the simplest solution.
5 files changed, 7 insertions(+), 7 deletions(-)
013c815 chore: work around parameterized parser syntax kinds
We should find a better solution for calling parameterized parsers such
as
matchAlt
than these helper definitions that confuse the antiquotations.6 files changed, 16 insertions(+), 16 deletions(-)
debb002 fix: incorrect antiquotation kind annotations
Apparently, none of them led to incorrect syntax trees, but
TSyntax
still disapproves.
8 files changed, 33 insertions(+), 33 deletions(-)
ee98c91 chore: work around
for
type inferenceIt seems type information often flows from the body to the loop
variable, which is problematic with coercions.
3 files changed, 3 insertions(+), 3 deletions(-)
869ecdf chore: postpone TSyntax adoption for some parts
The namespace
TSyntax.Compat
can be opened for a coercionSyntax -> TSyntax k
for anyk
, as otherwise this PR would never be done.16 files changed, 25 insertions(+), 9 deletions(-)
e71e4ac fix: unclear TSyntax breakage
1 file changed, 1 insertion(+), 1 deletion(-)
4efeef2 refactor: adapt raw syntax manipulations to TSyntax
Sometimes there's just no structure to work on
15 files changed, 49 insertions(+), 44 deletions(-)
5f415af refactor: remove some unnecessary antiquotation kind annotations
These are just the ones I stumbled upon, there should be a lot more now
rendered obsolete by the coercions.
7 files changed, 12 insertions(+), 13 deletions(-)
ffdf7ae refactor: strengthen
Syntax
signaturesMost notable change:
Quote
is now parameterized by the target kind.Which means that
Name
etc. could actually have differentimplementations for quoting into
term
andlevel
, if that need everarises.
30 files changed, 162 insertions(+), 154 deletions(-)
233669b chore: work around
macro
limitationsIt would be nice if
macro
was as expressive as syntax quotations, butright now it's not.
4 files changed, 15 insertions(+), 11 deletions(-)