Summary

Exported syntaxes are not fully hygienic

Metadata

Attachments

Description

Modules exporting syntaxes generated by syntaxes are not fully hygienic as the serialization into module-name.import.scm uses strip-syntax on module's sexports.

Minimal (Working) Example

Attached as follows:

mwe-ok.scm - single file where the macros show expected behavior

mwe-ko-common.scm - module with the macro generating macros mwe-ko-one.scm - first macro generated by the macro from common module mwe-ko-two.scm - second macro generated by the macro from module "one" mw-ko-run.scm - should behave like mwe-ok.scm, shows binding collisions

How to run

Reference (working) module:

 csi -q -b mwe.ok.scm

Multiple modules with problems:

 csc -P -J mwe-ko-common.scm
 csc -P -J mwe-ko-one.scm
 csc -P -J mwe-ko-two.scm
 csi -q -b mwe-ko-run.scm

Changes and comments

[2024-02-22 21:44:47 UTC] joe attached mwe-ok.scm (description=Working example.)

[2024-02-22 21:45:21 UTC] joe attached mwe-ko-common.scm (description=Non-working example, module with base syntax.)

[2024-02-22 21:45:47 UTC] joe attached mwe-ko-one.scm (description=Non-working example, module with first generated syntax.)

[2024-02-22 21:46:04 UTC] joe attached mwe-ko-two.scm (description=Non-working example, module with second generated syntax.)

[2024-02-22 21:46:23 UTC] joe attached mwe-ko-run.scm (description=Non-working example, main module to run.)

[2024-04-03 09:53:14 UTC] sjamaan wrote:

The problem is clearly strip-syntax - that should not be used. It's used because we don't want to emit gensymed names, as those won't be resolvable when loading the import library (that's a different compilation pass, which doesn't have the same aliases database).

A potential solution might involve something akin to `canonicalize-expression` on the syntax form, leaving any unresolved symbols as is (so keeping the gensymed aliases in place). There'd still be a risk of capture since those names won't be gensymed anymore, but it'd be less likely since they'd still be obfuscated.

I think if this works, we won't need the eval for the `module-import-forms` anymore either, as everything will be fully resolved.

Finally, I think we'd do well to simplify this example a bit. The code is quite hard to follow.

[2024-04-03 10:16:14 UTC] sjamaan wrote:

Replying to sjamaan: > A potential solution might involve something akin to `canonicalize-expression` on the syntax form

Hm, after thinking about this some more, I believe this would require teaching the compiler about `syntax-rules` and how to canonicalize its "templates".

Somehow that "feels" Very Wrong - we don't want to have to special case something like this. Users should be able to add their own expanders without requiring a special case for it.

[2025-11-03 06:44:13 UTC] sjamaan attached define-alist.scm (description=define-alist-macro doesn't work the same when compiled and interpreted)

[2025-11-03 06:45:56 UTC] sjamaan wrote:

Added a new example which breaks similarly. The code is a bit simpler than the initial example, so it's worth adding.

If you put the code in a module and compile the module with `-s`, then import it in the interpreter, the resulting expansion is different.