The issue isn't actually with the `(_ (x y))` pattern---it's with the
`#'(require (x y))` template.

When `require` is passed a module path like `(file "test1.rkt")`, it
introduces any identifiers [just `ok` in this case] with the same lexical
context of the module path itself[1].

The issue is that the expansion of `req2` adds a macro introduction scope
to the `(file "test1.rkt")` syntax object. Since the module path has an
additional scope, `ok` will have an additional scope; it won't bind the
`ok` from test2.rkt, and we get an unbound identifier error.

With `req1`, the parentheses around (file "test1.rkt") in the expanded code
come from the use site of the macro, so the `ok` identifier will have the
expected lexical context.

With `req2`, the parentheses around (file "test1.rkt") in the expanded code
come from the macro itself, not from the use site of the macro. Notice the
difference: in `(require x)` the parentheses are "in the x", but in
#'(require (x y)) the parentheses are from the (#') template.

You may be able to achieve your end goal using make-require-transformer[2],
which would probably end up being much nicer than what I'm about to go into.

Alternatively you could resort to using the unhygenic `datum->syntax` to
ensure that the resulting syntax object doesn't have the extra macro
introduction scope. I've added some checks before the template to ensure
that the forms passed to the macro are of the proper shape.

```
(define-syntax (req2 stx)
  (syntax-case stx ()
    [(_ (x y))
     ; throw a "bad syntax" error if the
     ; arguments are incorrect
     (and (free-identifier=? #'x #'file)
            (string? (syntax-e #'y)))
     #`(require
         #,(datum->syntax
            ; create the syntax object (x y)
            ; using the lexical context of y
            #'y
            (list #'x #'y)))]))
```

You may want to use `syntax-parse` instead, which makes these sorts of
checks much simpler to write, and usually gives better error messages than
"bad syntax".

```
(require (for-syntax racket/base syntax-parse))
(define-syntax (req2 stx)
  (syntax-parse stx
    [(_ ((~literal file) y:str))
     #`(require #,(datum->syntax #'y (list #'file #'y)))]))
```

---
[1] `module-path` part under the `require` section from
https://docs.racket-lang.org/reference/require.html?q=require#%28form._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._require%29%29
[2]
https://docs.racket-lang.org/reference/stxtrans.html?q=require%20transfo#%28def._%28%28lib._racket%2Frequire-transform..rkt%29._make-require-transformer%29%29



On Sun, Jul 12, 2020 at 8:18 PM Roman Klochkov <kalimehta...@gmail.com>
wrote:

> I try to make a macro, that expands to the require form.
>
> I put in test1.rkt
> ```
> #lang racket/base
> (provide ok)
> (define ok 1)
> ```
>
> I put in test.rkt
> ```
> #lang racket
> (define-syntax (req1 stx)
>   (syntax-case stx ()
>     [(_ x) #'(require x)]))
>
> (define-syntax (req2 stx)
>   (syntax-case stx ()
>     [(_ (x y)) #'(require (x y))]))
>
> (req2 (file "test1.rkt"))
> ok
> ```
>
> When I run it, I have the error: ok: unbound identifier
>
> If I change `req2` to `require` or to `req1`, then it returns 1 as should.
>
> What's wrong with (_ (x y)) pattern ?
>
> --
> You received this message because you are subscribed to the Google Groups
> "Racket Users" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to racket-users+unsubscr...@googlegroups.com.
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/racket-users/af6dcad0-69ff-406f-8183-dc691d302a5eo%40googlegroups.com
> <https://groups.google.com/d/msgid/racket-users/af6dcad0-69ff-406f-8183-dc691d302a5eo%40googlegroups.com?utm_medium=email&utm_source=footer>
> .
>

-- 
You received this message because you are subscribed to the Google Groups 
"Racket Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to racket-users+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/racket-users/CACehHmCq2dsK1gY8W0tVRMBtNpttGD0d2UpK6AmN2PvVMUm6mA%40mail.gmail.com.

Reply via email to