leif
2019-10-30 17:28:37

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


leif
2019-10-30 17:28:40
#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)

leif
2019-10-30 17:29:26

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


leif
2019-10-30 17:29:49

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


leif
2019-10-30 17:57:00

For reference, the error you get is:


leif
2019-10-30 17:57:04
. 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

mflatt
2019-10-30 18:27:08

@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.


leif
2019-10-30 20:13:33

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


mflatt
2019-10-30 20:18:57

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).


leif
2019-10-30 20:28:15

I see. Which is what makes this work:


leif
2019-10-30 20:28:18
#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)

leif
2019-10-30 20:29:28

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


leif
2019-10-30 20:31:08

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


spdegabrielle
2019-10-30 22:44:58

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’


mflatt
2019-10-30 22:48:49

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.


mflatt
2019-10-30 22:49:19

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)])


mflatt
2019-10-30 22:49:48

but probably with syntax-shift-phase-level.


mflatt
2019-10-30 22:50:44

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


leif
2019-10-30 23:19:55

@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))

leif
2019-10-30 23:20:00

But that leads to this question:


leif
2019-10-30 23:20:44

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


leif
2019-10-30 23:21:35

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


mflatt
2019-10-30 23:24:10

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


leif
2019-10-30 23:26:40

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


leif
2019-10-30 23:28:43

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


leif
2019-10-30 23:29:54

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


leif
2019-10-30 23:30:15

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


mflatt
2019-10-30 23:32:45

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


notjack
2019-10-30 23:34:57

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?


leif
2019-10-31 00:09:59

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


leif
2019-10-31 00:10:45

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


leif
2019-10-31 00:12:26

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


notjack
2019-10-31 00:15:23

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


notjack
2019-10-31 00:16:19

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


notjack
2019-10-31 00:16:30

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


sorawee
2019-10-31 06:48:54

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?