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