I just wanted to follow up to say that I finally got this working! I 
finally re-implemented all of my non-hygienic macros with syntax-parse, 
which resolved the unbound identifiers.

Once again, thanks to everyone who offered help and suggestions.

-- Jon

On Sunday, August 18, 2019 at 8:01:36 PM UTC-4, Jonathan Simpson wrote:
>
> Thanks very much for this! I hadn't considered the effect that stripping 
> the syntax information from the input to query would have. It has always 
> been a goal of mine to go back and rewrite all the macros -- and especially 
> the ugly stuff you mentioned in expander-utils.rkt -- with syntax-parse. 
> Your example should help me with that.
>
> The parse-levels and transform-levels functions in expander-utils.rkt 
> might be difficult to write in syntax-parse, although I'd love to do it 
> that way if possible. Would replacing my s-expr manipulation to operate on 
> syntax objects(via syntax->list, stx-car, and so on) achieve the same 
> result? Regardless, I will look into syntax-parse because I don't 
> particularly like what I have now and adding more complication to it is not 
> something I'd relish doing.
>
> -- Jon
>
>
> On Sunday, August 18, 2019 at 6:29:28 PM UTC-4, Sorawee Porncharoenwase 
> wrote:
>>
>> Surely defining a recursive function with a macro is a fairly common 
>>> occurrence. It is the expansion of the query macro within the function that 
>>> appears to be the problem. The syntax object passed to query has its own 
>>> lexical environment that doesn't include the containing function. This is 
>>> the point of hygiene I guess. I'm not exactly sure how to use it, but would 
>>> local-expand be a method to expand query in it's surrounding lexical 
>>> environment?
>>>
>> It is, and normally it’s not a problem because people generally write 
>> macros hygienically. However, in your case, several macros are written in 
>> defmacro-style (syntax->datum the whole syntax object to S-expression, 
>> and then manipulate the S-expression instead). That is usually the cause of 
>> problems.
>>
>> Here’s an example of how to write module-begin hygienically without 
>> using syntax->datum:
>>
>> ......
>>
>> ;; my own macro implementations to demonstrate that it works
>>
>> (define-syntax (named-query stx)
>>   (syntax-parse stx
>>     ;; make definition
>>     [(_ ({~datum name} name) e) #'(define (name) e)]))
>>
>> (define-syntax (query stx)
>>   (syntax-parse stx
>>     [(_ e) #'e]))
>>
>> (define-syntax (line stx)
>>   (syntax-parse stx
>>     [(_ e) #'e]))
>>
>> (define-syntax (use-name stx)
>>   (syntax-parse stx
>>     ;; add application
>>     [(_ e) #'(e)]))
>>
>> ;; end my own macro implementations
>>
>> (define-syntax (wrap-with-delimiter-print stx)
>>   (syntax-parse stx
>>     [(_ expr) #'(when* expr (printf "*** "))]))
>>
>> (define-syntax (magic-module-begin stx)
>>   (define (query? expr)
>>     (syntax-parse expr
>>       [({~literal query} . _) #t]
>>       [_ #f]))
>>
>>   (define (named-query? expr)
>>     (syntax-parse expr
>>       [({~literal named-query} . _) #t]
>>       [_ #f]))
>>
>>   (syntax-parse stx
>>     [(_ ({~datum magic} exprs ...))
>>      #:with (queries ...) (filter query? (attribute exprs))
>>      #:with (named-queries ...) (filter named-query? (attribute exprs))
>>      #'(#%module-begin
>>         named-queries ...
>>         (define (magic-query) (or queries ...))
>>         (define (magic-query-run-all)
>>           ; any-true? creates a binding for last-level-offset which we 
>> probably don't want here. investigate.
>>           (any-true? (wrap-with-delimiter-print queries) ...))
>>         (provide magic-query magic-query-run-all))]))
>>
>> (provide
>>  (except-out (all-from-out racket/base) #%module-begin) 
>>  (rename-out [magic-module-begin #%module-begin])
>>  use-name query named-query line)
>>
>> Then this code works correctly:
>>
>> #lang racket
>>
>> (module magic-mod magic/expander
>>   (magic
>>    (named-query (name tga-image) (line 1))
>>    (named-query (name test-scope) (line (use-name tga-image)))
>>    (query (use-name test-scope))))
>>
>> [image: Screen Shot 2019-08-18 at 15.18.35.png]
>>
>> For your code, the next thing I would suggest looking into is to avoid 
>> using syntax->datum in the query macro (and also the whole S-expression 
>> mangling in expander-utils) and use syntax-parse on the syntax object 
>> instead. As a bonus, syntax-parse would let you avoid things like 
>> cadddadr.
>>  
>>
>>>
>>> -- Jon
>>>
>>>
>>> On Wednesday, August 14, 2019 at 10:49:35 PM UTC-4, Jonathan Simpson 
>>> wrote:
>>>>
>>>> I will take a look at this as well. It may be a few days before I have 
>>>> time to devote to this again, but I appreciate everyone's help so far.
>>>>
>>>> -- Jonathan
>>>>
>>>> On Wednesday, August 14, 2019 at 1:00:54 AM UTC-4, Matthew Butterick 
>>>> wrote:
>>>>>
>>>>>
>>>>> On 13 Aug 19, at 7:03 PM, Jonathan Simpson <jjsi...@gmail.com> wrote:
>>>>>
>>>>> In the following magic code, a new function(called a named query in 
>>>>> magic) tga-image is defined and later used inside the definition of the 
>>>>> function test-scope. The issue is that tga-image is an unbound identifier 
>>>>> in test-scope. If tga-image is used outside of a function there isn't a 
>>>>> problem because the syntax object passed to use has the binding. What I 
>>>>> would like to do is define tga-image at the top level.
>>>>>
>>>>>
>>>>>
>>>>>
>>>>> You might consider the technique described here, including the 
>>>>> `find-unique-var-ids` function:
>>>>>
>>>>> https://beautifulracket.com/basic-2/variables-and-input.html
>>>>>
>>>>> Since you're using `brag`, you can wrap your future identifiers in, 
>>>>> say, an `id` rule that you splice away in the grammar. So your parse tree 
>>>>> ends up the same, but now that `id` rule leaves a residue as a syntax 
>>>>> property. 
>>>>>
>>>>> Then, as part of your `#%module-begin` prep work, you can use this 
>>>>> property to pull out the identifiers and write them into the top level of 
>>>>> your new module as `define` expressions (with dummy values, that would 
>>>>> get 
>>>>> replaced later with `set!`). 
>>>>>
>>>>> There may be a way of accomplishing the same thing more elegantly with 
>>>>> syntax lifts and captures. Like the lost city of El Dorado, I searched 
>>>>> for 
>>>>> this beauty, but expired on the jungle floor before discovering it. Since 
>>>>> then, however, many people smarter than me have seen that page, so by 
>>>>> Cunningham's Law, if there were a better method, I probably would've been 
>>>>> told by now. 
>>>>>
>>>>>
>>>>>
>>>>>
>>>>> -- 
>>> 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...@googlegroups.com.
>>> To view this discussion on the web visit 
>>> https://groups.google.com/d/msgid/racket-users/cef06a2b-0d07-462d-806f-1d9804fca973%40googlegroups.com
>>>  
>>> <https://groups.google.com/d/msgid/racket-users/cef06a2b-0d07-462d-806f-1d9804fca973%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/c9d2f0e8-c92e-43a5-bd26-20f5272d2a74%40googlegroups.com.

Reply via email to