Hi all! --------------------
TL;DR: if you're struggling when debugging scopes, I wrote a couple of utilities to help: (+scopes stx) shows the scopes in a readable manner, (print-full-scopes) gives a summary of these scopes, and (make-named-scope string-or-symbol) creates a fresh scope annotated with a name, to track it more easily in the macro stepper or in (print-full-scopes). Docs here: http://docs.racket-lang.org/debug-scopes/ -------------------- When developing unhygienic macros, it frequently occurs that an extra, unwanted scope is present on one part of the output: In the macro's result, one might expect two identifiers to bind one another, but they won't because of that extra scope. The reasons for this occurring are rare, but varied: * Using a macro which forgets to remove the use-site scope (with syntax-local-identifier-as-binding) from an identifier which ends up in a binding position. Most of the time this is not a problem, but in a few corner cases this can be a problem. * Template metafunctions (from syntax/parse/experimental/template) flip their own mark on the output, but don't provide a way to cancel that mark (i.e. they are forcefully hygienic in a way). * Voluntarily applying a (make-syntax-introducer) in one place, and mistakenly forgetting to apply it in the other * And so on. While the fix for these problem is often trivial (flip the right scope in the right place), finding the source of the error can be a difficult endeavour. A few things could be changed to help debugging: * The snip% that shows up when a syntax object is display-ed shows a wealth of information about the syntax object and its subparts, but not the scopes present on them. * The macro-debugger/syntax-browser does show this information, but can only be called from phase 0 (rendering difficult attempts to inspect syntax objects in the middle of the execution of a transformer function) * The macro stepper is a bit cumbersome to use for this purpose: you have to click on the two identifiers one after another, and compare the (potentially long) list of scopes. Also, it rarely crashes, but according to Murphy's law will only do so when you're debugging the hardest issue ;-) * The scopes as printed by syntax-debug-info and the macro debugger are 6-digit numbers which are difficult to compare at a glance * These numbers say nothing about which macro introduced which scope — names would be a bliss, but alas (make-syntax-introducer) does not accept an optional name argument, and the auto-generated macro and use-site scopes are not annotated with the macro's name. I wrote a small package, https://pkgd.racket-lang.org/pkgn/package/debug-scopes , which helps with the last two issues: * The (+scopes stx) function returns a string, where each identifier is adorned with the scopes it has, using a succinct notation for ranges of scopes, which is practical for comparing the sets of scopes on two identifiers at a glance (see the docs for more details). * The (print-full-scopes) function prints a table making the correspondance between that succinct notation and the traditional syntax-debug-info notation * The (make-named-scope string-or-symbol) function creates a fresh scope like (make-syntax-introducer), but annotates it with a name. It is based on a hack: it creates a module with that name on the fly, extracts the module scope, and discards the module. This works because module scopes are annotated with their name in the macro debugger, unlike other kinds of scopes. This hack is likely slow, but if someday (make-syntax-introducer) supports an optional name, we'll rely on that instead. * As an experimental feature, (require debug-scopes/named-scopes/override) overrides define-syntax and syntax-local-introduce, so that the implicit macro scope bears the name of the macro (it does not affect the use-site scope, as that one is handled specially by definition contexts). This feature might behave badly with other for-syntax functions which use the non-overridden version of syntax-local-introduce, so use with care. I hope this can help others while debugging scope-related issues, which I found to be the most difficult aspect of unhygienic macro development. Happy new year! Georges Dupéron -- You received this message because you are subscribed to the Google Groups "Racket Users" group. To unsubscribe from this group and stop receiving emails from it, send an email to racket-users+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.