-
Notifications
You must be signed in to change notification settings - Fork 39
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
macros: make quote
a proper quasi-quoting operator
#1393
Conversation
* no symbol binding takes placed for unquoted expressions * identifiers in definition positions are not turned into gensyms Internally, no templates are involved, nor `getAst`. `sem` extracts all unquoted expressions from the quoted AST, wraps them in `newLit` calls, and delegates the substitution work to the `quoteImpl` procedure, which is run in the VM.
Include `nkNimNodeLit` in the set of nodes to ignore.
The problem is that it doesn't work with objects that have private fields, which would be a regression. The internal `evalToAst` magic is introduced, which translates to an `opcDataToAst` instruction in the VM.
Symbols that should be bound early need to explicitly use `bindSym`, and identifiers that need to be unique require usage of `genSym`.
It's used by a `quote`d AST, and since some of the type's fields are already exported, the type itself is exported too, fixing the "undeclared identifier" error.
The line information of the error now points to the correct expression.
The `mysym` definition outside the macro is unnecessary for the reproducer of the original issue, so removing it is fine.
The usage of `quote` relied on identifiers in definitions being gensym'ed. To prevent redefinitions, the macro outputs are now wrapped in blocks.
Is there some rationale for this? I expect that this will make using |
That's just a consequence of |
Are there plans to allow gensym to happen to unquoted identifiers in the future? |
No, at least not from my side. Edit: For my answer, I've assumed that with "unquoted identifier" you mean "identifiers that are not accent-quoted". In the meantime, you can either use template gensymQuote(bl: untyped): untyped {.dirty.} =
block:
let name = genSym(nskTemplate, "templ")
quote do:
template `name`(): untyped =
bl
`name`() Depending on the quoted AST, you can also just wrap the code in an |
Per the discussion in matrix, concern around being able to get the old behaviour have been resolved per @zerbina's solution.
|
The previous comment is no longer relevant.
Code was added to `macros.nim`, so the line where the offending node originates from (the `newNimNode` call) changed.
/merge |
Merge requested by: @zerbina Contents after the first section break of the PR description has been removed and preserved below:
|
## Summary Add `stamp` to `std/macros` , which takes a template body and applies it immediately. This is the same behaviour as the previous `quote` that was changed after #1393. ## Details After #1393 we have a hole in the stdlib for `quote` -like interpolation but with automatic binding of symbols to reduce boilerplate. Various libraries within the ecosystem such as `criterion` and `npeg` have found the feature useful and extensively employ it. Reintroduces old `quote` behavior as `stamp` , without support for custom operators and explicitly document the template-like nature of `stamp` 's body as well as its pitfalls. This macro was originally written and shared to Matrix by @zerbina. --------- Co-authored-by: zerbina <[email protected]> Co-authored-by: Saem Ghani <[email protected]>
Summary
quote
now keeps the quoted block as is, which means that:scopes
stay as is
.gensym
and.inject
pragmas within the quoted block don't affectthe AST
Symbols thus need to be bound or created explicitly, via
bindSym
andgenSym
, respectively. This is a breaking change.Details
Motivation For The Change
quote
's scope being bound is error-prone, leadingto confusing compilation errors
quote
already said it does quasi-quoting (even though it didn't)
template evaluation
New Behaviour
are turned into gensyms
Implementation
semQuoteAst
transforms thequote
call into a call to the internalquoteImpl
procedureextracted unquoted expression are passed as the remaining arguments
evalToAst
magic procedure is used for evaluatingthe unquoted expressions.
newLit
cannot be used here, as the treesit produces for
object
values are only valid when all the type'sfields are exported
in-VM, by
quoteImpl
Standard Library And Test Changes
symbol binding and gensym behaviour; they're changed to use
bindSym
or
genSym
. Outside-visible behaviour doesn't changet7875.nim
test relied on the gensym behaviour. The definitionoutside the macro is not relevant to the issue the test guards
against, so it can just be removed
tsizeof.nim
are wrapped in blocks in order toprevent the identifiers from colliding