
@mflatt I think I found a bug in syntax-binding sets:

#lang racket/load
(module m1 racket
(provide m1)
(define-syntax (m1 stx)
#'(begin
(provide m2)
(define-syntax (m2 stx)
#'42))))
(module m2 racket
(require 'm1)
(m1))
(module m3 racket
(require 'm2)
(define-for-syntax this-module
(variable-reference->module-path-index (#%variable-reference)))
(define-for-syntax (forge-identifier modpath sym)
(syntax-binding-set->syntax
(syntax-binding-set-extend (syntax-binding-set) sym 0 modpath)
sym))
(define-syntax (m stx)
(forge-identifier (module-path-index-join ''m2 #f) 'm2))
(m))
(module m3-good racket
(require 'm2)
(m2))
(require 'm3)
;(require 'm3-good)

Namely, they seem to fail when trying to refer to macro introduced macros.

(If, for example, I alter it to refer to m1
instead of m2
, it works.

For reference, the error you get is:

. instantiate-linklet: mismatch;
reference to a variable that is uninitialized;
possibly, bytecode file needs re-compile because dependencies changed
name: m2
exporting instance: 'm2
importing instance: 'm3

@leif A macro-introduced binding (define m ...)
or (define-syntax m ....)
will not have the symbolic name 'm
. Note that (require 'm2)
(println (identifier-binding #'m2))
prints 'm.1
as the second item of the list, where the .1
has been added to help highlight that it’s not just 'm
. It’s an unreadable (but interned) symbol.
The symbolic name 'm
is reserved for a non-macro-introduced definition. Each macro-introduced definition in a module where the syntactic form has a symbol 'm
will bind to a distinct unreadable symbol 'm.1
, 'm.2
, etc.

@mflatt So then why doesn’t the .1
show up when I do (module->exports "m2")
?

module->exports
shows you the symbolic export name, as opposed to the symbolic definition name. It’s essentially the same reason that 'm1
shows up as the fourth result from identifier-binding
. If you change (provide m2)
to (provide (rename-out [m2 other])
, then 'other
will show up in module->exports
or as the fourth result from (identifier-binding #'other)
, but 'm2.1
will still be the second result from (identifier-binding #'other)
.

I see. Which is what makes this work:

#lang racket/load
(module A racket
(define x 5)
(provide (rename-out [x y])))
(module B racket
(define-for-syntax this-module
(variable-reference->module-path-index (#%variable-reference)))
(define-for-syntax (forge-identifier modpath sym)
(syntax-binding-set->syntax
(syntax-binding-set-extend (syntax-binding-set) sym 0 modpath)
sym))
(require 'A)
(define-syntax (m stx)
(forge-identifier (module-path-index-join ''A #f) 'x))
(m))
(require 'B)

So, is there any way I can change syntax-binding-set
s to respect export name rather than the definition name?

Which is (as I understand it) how syntax-local-lift-require
works?

Hi attempts to access the 64bit macos build at https://www.cs.utah.edu/plt/snapshots/current/installers/racket-7.5.0.4-x86_64-macosx.dmg returns ‘Forbidden’

I think an rsync got interrupted, and then the build didn’t complete for a couple of days due to web-server
changes. It should recover tomorrow, and I’ll adjust the script to try rsync
a few times to handle failures.

Not syntax-local-lift-require
because you don’t want to create a module dependency, right? The only idea I have right now is expand
, maybe something like (syntax-case (expand `(module m racket/kernel (#%require 'm2) (quote-syntax m2))) ()
[(mod _ _ (mod-beg _ (q-s id))) (identifier-binding #'id)])

but probably with syntax-shift-phase-level
.

It would make sense for a binding set to support a require
-like operation, I think.

@mflatt Okay, it looks like I can use the #:source-symbol
and #:nominal-source-symbol
arguments to construct a binding set based on the provide binding rather than the define one, such as in:
(identifier-binding
(syntax-binding-set->syntax
(syntax-binding-set-extend (syntax-binding-set) 'renamed 0
(module-path-index-join "a1.rkt" (variable-reference->module-path-index
(#%variable-reference)))
#:source-symbol 'def
#:nominal-symbol 'renamed)
'renamed))

But that leads to this question:

Is it possible to find the definition binding from the provided one?

Ideally without needing to visit the defining module in the first place. At least not until run time.

I don’t think that information is currently available. It could be provided by something like module->exports
, but module->exports
doesn’t.

I see. It seems like that’s needed to forge identifiers from other modules.

Oh, I just noticed that you replied to my previous comment (from a few hours back)

It does look like your snippet might work, although it does require a visit to the module before hand.

(Which is a problem in the case of the ‘self’ module, if that makes any sense?)

Probably the right solution is to expand the result of module->exports
to have the relevant symbol.

On the subject of module->exports
, I find it really, really difficult to understand what data it’s returning, since it’s a bunch of nested lists of lists with irregular shapes. Does anyone else have that problem?

@mflatt Makes sense. Although IIRC, module->export
only works if the module is already loaded into the current namespace, yes?

@notjack Its just two lists of phase-identifier pairs.

The first list is provided ones, and IIRC, the second being reprovided ones.

They’re not phase-identifier pairs, they’re phase-list pairs

And the first list is exported variables, the second is exported syntax

My point is, it’s hard to keep straight :p

raco test
sets current-directory
to the test file’s directory, as documented. This is understandable, but sometimes I really want to know what current directory I am in. For instance, raco test ++args ./foo/bar.txt sub/main.rkt
specifies ./foo/bar.txt
relative to .
, not sub
. Is there a way to retrieve the actual current directory?