[racket] getting one macro to tell another macro to define something

From: J. Ian Johnson (ianj at ccs.neu.edu)
Date: Fri Aug 1 20:12:16 EDT 2014

Ah, okay, so... this macro expander you give is fundamentally flawed because match-define does an initial parse (which uses the match expander) to get the identifiers it is going to define. So, when you expand to x3 as the match pattern, you end up returning x3 as one of the values that the match-define -> define-values is going to define. It does not ever define "x" as anything because that was just arbitrary syntax that was given to the match expander. This x3 is x3 definition leads to a use-before-initialization error.

Do you have a different example that doesn't fail in this way?
-Ian
----- Original Message -----
From: "J. Ian Johnson" <ianj at ccs.neu.edu>
To: "J. Ian Johnson" <ianj at ccs.neu.edu>
Cc: "racket users list" <users at racket-lang.org>, "Alexander D. Knauth" <alexander at knauth.org>
Sent: Friday, August 1, 2014 7:47:04 PM GMT -05:00 US/Canada Eastern
Subject: Re: [racket] getting one macro to tell another macro to define something

Okay, define-forms.rkt had some uses of parse outside of gen-match's "go" which sets the parameter, so I fixed that. Now it turns out the docs are imprecise for make-syntax-delta-introducer's first argument. It wants an identifier rather than an arbitrary piece of syntax. Not sure why that's necessary. I'm going to stop and wait for ryanc or mflatt to respond to this thread. I'm out of ideas.
-Ian
----- Original Message -----
From: "J. Ian Johnson" <ianj at ccs.neu.edu>
To: "Alexander D. Knauth" <alexander at knauth.org>
Cc: "racket users list" <users at racket-lang.org>, "J. Ian Johnson" <ianj at ccs.neu.edu>
Sent: Friday, August 1, 2014 7:30:10 PM GMT -05:00 US/Canada Eastern
Subject: Re: [racket] getting one macro to tell another macro to define something

Well, I just hacked racket/match to allow match-expanders to take a third argument that is the introducer for the application. No permutation of mark applications works, I think since syntax-local-introduce does not include all the marks from the top use of match-define all the way through internal macros to the transformer call. I'm currently looking into getting a delta-introducer sent to the transformer that has the delta between the original match syntax and the match-expander syntax, but I'm fighting the implementation in actually getting the orig-stx parameter set to the right thing. 
-Ian
----- Original Message -----
From: "Alexander D. Knauth" <alexander at knauth.org>
To: "J. Ian Johnson" <ianj at ccs.neu.edu>
Cc: "racket users list" <users at racket-lang.org>
Sent: Friday, August 1, 2014 7:17:53 PM GMT -05:00 US/Canada Eastern
Subject: Re: [racket] getting one macro to tell another macro to define something


I found this on line 2327 of racket/src/racket/src/env.c: 

static Scheme_Object * 
local_introduce ( int argc , Scheme_Object * argv []) 
{ 
Scheme_Comp_Env * env ; 
Scheme_Object * s ; 


env = scheme_current_thread -> current_local_env ; 
if ( ! env ) 
not_currently_transforming ( "syntax-local-introduce" ); 


s = argv [ 0 ]; 
if ( ! SCHEME_STXP ( s )) 
scheme_wrong_contract ( "syntax-local-introduce" , "syntax?" , 0 , argc , argv ); 


if ( scheme_current_thread -> current_local_mark ) 
s = scheme_add_remove_mark ( s , scheme_current_thread -> current_local_mark ); 


return s ; 
} 
What would happen if match-expander-transform somehow set scheme_current_thread -> current_local_mark to the mark produced by the new syntax-introducer? And would that even be possible? (without fundamental changes to racket) 



On Aug 1, 2014, at 6:45 PM, J. Ian Johnson < ianj at ccs.neu.edu > wrote: 


Well one problem is expander application his its own mark to deal with, so you can't cancel the mark on x. 

https://github.com/plt/racket/blob/master/racket/collects/racket/match/parse-helper.rkt#L157 

Another problem is expecting the implementation of match-define to not have any inner macros that would change syntax-local-introduce to a less helpful extent. 
What would be ideal is if racket/match could change some "parameter" so that syntax-local-introduce used the introducer defined in the above link, since the generated temporary does not have x's mark that x has annihilated. Instead x's mark will be added to tmp after the transformer returns, and there's nothing you can do about it :( 

-Ian 
----- Original Message ----- 
From: "Alexander D. Knauth" <alexander at knauth.org> 
To: "J. Ian Johnson" <ianj at ccs.neu.edu> 
Cc: "racket users list" <users at racket-lang.org> 
Sent: Friday, August 1, 2014 6:31:59 PM GMT -05:00 US/Canada Eastern 
Subject: Re: [racket] getting one macro to tell another macro to define something 

Well, if the match-expander is invoked in the “dynamic extent” of the match-define form, then would syntax-local-introduce apply that syntax-mark? 

On Aug 1, 2014, at 6:20 PM, J. Ian Johnson <ianj at ccs.neu.edu> wrote: 



Well that's a pickle. I can tell you that (mac . args) gets expanded as (X[mac^m] . X[args^m])^m where m is a fresh mark and X expands a form. If m is applied to something with m already, they annihilate each other (see Syntactic Abstraction in Scheme for how this totally works). 
The syntax-local-introduce form allows you to apply the macro application's mark to an arbitrary piece of syntax, so later on the application's mark will annihilate it and voila`, it's like it was textually given to the macro application itself. 

Here, however, a match expander is not treated as a macro invocation. There is no mark for that match-expander use to introduce. There is, however, the mark from match-define that you'll want to introduce to this temporary you've generated. I think. I haven't quite worked out how to make this work. 
-Ian 
----- Original Message ----- 
From: "Alexander D. Knauth" <alexander at knauth.org> 
To: "racket users list" <users at racket-lang.org> 
Sent: Friday, August 1, 2014 5:55:57 PM GMT -05:00 US/Canada Eastern 
Subject: Re: [racket] getting one macro to tell another macro to define something 





On Aug 1, 2014, at 5:37 PM, J. Ian Johnson < ianj at ccs.neu.edu > wrote: 


It's best to expand into a begin-for-syntax that does the desired mutation, rather than mutate within the transformer. You currently _cannot_ do this outside top level forms. 



The reason I can’t do that is because in the real program, sender is actually a match-expander. 


You are also right about the marks. The call to receiver adds additional marks to the definitions that it pulls out, so you'll need to apply syntax-local-introduce. ... 




On Aug 1, 2014, at 5:39 PM, Ryan Culpepper < ryanc at ccs.neu.edu > wrote: 


Use syntax-local-introduce when putting syntax into a side-channel or getting it back out across macro calls. This only matters when the syntax represents a definition or more generally contains binders whose references are not all in the same syntax. 
... 


Thanks, the syntax-local-introduce got it working for that example, but for some reason it’s not working when sender is a match-expander. 

I’m still not very clear on when to use syntax-local-introduce and when not to, or even what it does (other than get that example working), so could someone point me in the right direction? 



#lang racket 
(require racket/stxparam 
(for-syntax syntax/parse 
racket/syntax 
racket/set)) 
;; current-defs : (syntax-parameter-of (or/c set-mutable? #f)) 
(define-syntax-parameter current-defs #f) 
(define-match-expander sender 
(lambda (stx) 
(syntax-parse stx 
[(sender x) 
#:with tmp (generate-temporary #'x) 
(define defs (syntax-parameter-value #'current-defs)) 
(set-add! defs (syntax-local-introduce #'(define x tmp))) 
#'tmp]))) 
(define-syntax reciever 
(lambda (stx) 
(syntax-parse stx 
[(reciever) 
(define defs (syntax-parameter-value #'current-defs)) 
(with-syntax ([(def ...) (map syntax-local-introduce (set->list defs))]) 
#'(begin def ...))]))) 


(syntax-parameterize ([current-defs (mutable-set)]) 
(match-define (sender x) 1) 
(reciever) 
x) 


;x3: unbound identifier; 
; also, no #%top syntax transformer is bound in: x3 




____________________ 
Racket Users list: 
http://lists.racket-lang.org/users 




Posted on the users mailing list.