Am Fr., 25. Sept. 2020 um 23:27 Uhr schrieb John Cowan <[email protected]>:

>> What I have
>> been discussing with Jim lately is the following: If a library exports
>> an identifier `foo', one can access all (not renamed) identifiers that
>> are defined at the top-level of the library, namely through
>> (datum->syntax #'foo top-level-identifier-name) or a similar
>> construction for the given macro system that allows unhygienic
>> bindings. Therefore, not only the set exported identifiers but also
>> the top-level environment of a library is an observable quantity.
>
>
> I tried this in Guile with an R6RS library that defines trivial procedures 
> foo and bar and exports foo.  Evaluating (datum->syntax #'foo 'bar) gives me 
> #<syntax bar>, but I do not see how to invoke the procedure bound to bar.  
> Furthermore, if I try it with baz instead of bar, I get #<syntax baz>, pretty 
> much indistinguishable.  So it is not leaking even the names of top-level 
> bindings, never mind their values.  The same is true in Chez.

There are two issues here.

The first is that you don't want the bar and baz syntax objects at
run-time but at expand-time, so you have to change the phase level
using define-syntax, i.e. you have to produce the syntax objects in a
macro transformer, which is then fed into the expander.

The bigger issue is that I wrote my earlier paragraph without thinking
enough. The "forging" (datum->syntax #'foo top-level-identifier-name)
only works when foo has the correct syntactic environment. However,
the imported identifier foo has the syntactic environment of the
top-level environment of the importing library/program. So you have to
move the syntax definition for forging into the library with the
top-level-identifier:

$ cat test.sld
(define-library (test)
  (export get public)
  (import (scheme base)
          (srfi 211 syntax-case))
  (begin
    (define (public) 'public)
    (define (private) 'private)
    (define-syntax get
      (lambda (stx)
        (syntax-case stx ()
          ((_ id)
           (datum->syntax #'public (syntax->datum #'id))))))))
$ unsyntax-scheme -I .
Unsyntax 0.0.2.5-601a-dirty
Copyright (C) 2020 Marc Nieper-Wißkirchen

This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

#,> (import (test))
#,> (public)
public
#,> (private)
error: non procedure application: (#<undef>)
#,> (get private)
#<procedure private.17462>
#,> ((get private))
private

This doesn't change my original point, though: As it is generally
undecidable whether a top-level library exports a syntax like `get`, a
library defines not only its exports but also its top-level bindings.

#,> (define x 1)
#,> (import (srfi 211 syntax-case))
#,> (free-identifier=? #'x (datum->syntax #'public 'x))

This last example shows that the syntactic environment of the
*imported* identifier public is the one of the importing
library/module.

Marc

Reply via email to