@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-sets 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?